drf-to-mkdoc 0.1.6__tar.gz → 1.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of drf-to-mkdoc might be problematic. Click here for more details.
- drf_to_mkdoc-1.0.7/.pre-commit-config.yaml +8 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/PKG-INFO +1 -1
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/conf/settings.py +3 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/__init__.py +1 -1
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/apps.py +6 -2
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/conf/defaults.py +0 -1
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/conf/settings.py +8 -5
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/build_docs.py +61 -20
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/generate_docs.py +1 -2
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/generate_model_docs.py +1 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/common.py +27 -22
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/endpoint_generator.py +130 -131
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +3 -7
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc.egg-info/PKG-INFO +1 -1
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc.egg-info/SOURCES.txt +1 -0
- drf_to_mkdoc-1.0.7/pyproject.toml +214 -0
- drf_to_mkdoc-0.1.6/pyproject.toml +0 -80
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/.github/workflows/publish.yaml +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/CONTRIBUTING.md +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/LICENSE +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/MANIFEST.in +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/README.md +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/conf/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/conf/defaults.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/docs/customizing_endpoints.md +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/docs/serving_mkdocs_with_django.md +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/conf/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/generate_doc_json.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/management/commands/update_doc_schema.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/javascripts/endpoints-filter.js +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/accessibility.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/animations.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/base.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/endpoint-content.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/endpoints-grid.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/filter-section.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/fixes.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/layout.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/loading.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/responsive.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/sections.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/stats.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/tags.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/variables.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/extra.css +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/extractors/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/md_generators/__init__.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/md_generators/query_parameters_generators.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc/utils/model_generator.py +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc.egg-info/dependency_links.txt +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc.egg-info/requires.txt +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/drf_to_mkdoc.egg-info/top_level.txt +0 -0
- {drf_to_mkdoc-0.1.6 → drf_to_mkdoc-1.0.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: drf-to-mkdoc
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 1.0.7
|
|
4
4
|
Summary: Generate Markdown API docs from Django/DRF OpenAPI schema for MkDocs
|
|
5
5
|
Author-email: Hossein Shayesteh <shayestehhs1@gmail.com>
|
|
6
6
|
Maintainer-email: Hossein Shayesteh <shayestehhs1@gmail.com>
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
|
+
|
|
2
3
|
from .defaults import DEFAULTS
|
|
3
4
|
|
|
5
|
+
|
|
4
6
|
class DocBuilderSettings:
|
|
5
7
|
def __init__(self, user_settings_key="DOC_BUILDER", defaults=None):
|
|
6
8
|
self.user_settings_key = user_settings_key
|
|
@@ -15,4 +17,5 @@ class DocBuilderSettings:
|
|
|
15
17
|
def __getattr__(self, key):
|
|
16
18
|
return self.get(key)
|
|
17
19
|
|
|
20
|
+
|
|
18
21
|
drf_to_mkdoc_settings = DocBuilderSettings(defaults=DEFAULTS)
|
|
@@ -1,15 +1,19 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
1
3
|
from django.apps import AppConfig
|
|
2
4
|
|
|
5
|
+
logger = logging.getLogger()
|
|
6
|
+
|
|
3
7
|
|
|
4
8
|
class DrfToMkdocConfig(AppConfig):
|
|
5
9
|
default_auto_field = "django.db.models.BigAutoField"
|
|
6
10
|
name = "drf_to_mkdoc"
|
|
7
11
|
verbose_name = "DRF to MkDocs Documentation Generator"
|
|
8
|
-
|
|
12
|
+
|
|
9
13
|
def ready(self):
|
|
10
14
|
"""Initialize the app when Django starts."""
|
|
11
15
|
# Import management commands to register them
|
|
12
16
|
try:
|
|
13
17
|
import drf_to_mkdoc.management.commands # noqa
|
|
14
18
|
except ImportError:
|
|
15
|
-
|
|
19
|
+
logger.exception("Failed to import drf_to_mkdoc commands")
|
|
@@ -5,7 +5,6 @@ DEFAULTS = {
|
|
|
5
5
|
"MODEL_DOCS_FILE": "docs/model-docs.json", # Path to model documentation JSON file
|
|
6
6
|
"DOC_CONFIG_FILE": "docs/configs/doc_config.json", # Path to documentation configuration file
|
|
7
7
|
"CUSTOM_SCHEMA_FILE": "docs/configs/custom_schema.json", # Path to custom schema file
|
|
8
|
-
|
|
9
8
|
# Django apps - required, no default
|
|
10
9
|
"DJANGO_APPS": None, # List of Django app names to process
|
|
11
10
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
|
+
|
|
2
3
|
from drf_to_mkdoc.conf.defaults import DEFAULTS
|
|
3
4
|
|
|
5
|
+
|
|
4
6
|
class DRFToMkDocSettings:
|
|
5
7
|
required_settings = ["DJANGO_APPS"]
|
|
6
8
|
|
|
@@ -12,15 +14,15 @@ class DRFToMkDocSettings:
|
|
|
12
14
|
def get(self, key):
|
|
13
15
|
if key not in self.defaults:
|
|
14
16
|
raise AttributeError(f"Invalid DRF_TO_MKDOC setting: '{key}'")
|
|
15
|
-
|
|
17
|
+
|
|
16
18
|
value = self._user_settings.get(key, self.defaults[key])
|
|
17
|
-
|
|
19
|
+
|
|
18
20
|
if value is None and key in self.required_settings:
|
|
19
21
|
raise ValueError(
|
|
20
22
|
f"DRF_TO_MKDOC setting '{key}' is required but not configured. "
|
|
21
23
|
f"Please add it to your Django settings under {self.user_settings_key}."
|
|
22
24
|
)
|
|
23
|
-
|
|
25
|
+
|
|
24
26
|
return value
|
|
25
27
|
|
|
26
28
|
def __getattr__(self, key):
|
|
@@ -28,17 +30,18 @@ class DRFToMkDocSettings:
|
|
|
28
30
|
|
|
29
31
|
def validate_required_settings(self):
|
|
30
32
|
missing_settings = []
|
|
31
|
-
|
|
33
|
+
|
|
32
34
|
for setting in self.required_settings:
|
|
33
35
|
try:
|
|
34
36
|
self.get(setting)
|
|
35
37
|
except ValueError:
|
|
36
38
|
missing_settings.append(setting)
|
|
37
|
-
|
|
39
|
+
|
|
38
40
|
if missing_settings:
|
|
39
41
|
raise ValueError(
|
|
40
42
|
f"Missing required settings: {', '.join(missing_settings)}. "
|
|
41
43
|
f"Please configure these in your Django settings under {self.user_settings_key}."
|
|
42
44
|
)
|
|
43
45
|
|
|
46
|
+
|
|
44
47
|
drf_to_mkdoc_settings = DRFToMkDocSettings(defaults=DEFAULTS)
|
|
@@ -1,11 +1,12 @@
|
|
|
1
|
+
import shutil
|
|
1
2
|
import subprocess
|
|
2
3
|
from pathlib import Path
|
|
3
4
|
|
|
4
|
-
from django.conf import settings
|
|
5
|
-
from django.core.management.base import BaseCommand, CommandError
|
|
6
5
|
from django.apps import apps
|
|
7
|
-
from
|
|
6
|
+
from django.conf import settings
|
|
8
7
|
from django.core.management import call_command
|
|
8
|
+
from django.core.management.base import BaseCommand, CommandError
|
|
9
|
+
from your_app import drf_to_mkdoc_settings # Replace with your actual import
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
class Command(BaseCommand):
|
|
@@ -18,13 +19,13 @@ class Command(BaseCommand):
|
|
|
18
19
|
try:
|
|
19
20
|
apps.check_apps_ready()
|
|
20
21
|
except Exception as e:
|
|
21
|
-
raise CommandError(f"Django apps not properly configured: {e}")
|
|
22
|
+
raise CommandError(f"Django apps not properly configured: {e}") from e
|
|
22
23
|
|
|
23
24
|
base_dir = Path(settings.BASE_DIR)
|
|
24
25
|
site_dir = base_dir / "site"
|
|
25
26
|
mkdocs_config = base_dir / "mkdocs.yml"
|
|
26
27
|
mkdocs_config_alt = base_dir / "mkdocs.yaml"
|
|
27
|
-
|
|
28
|
+
|
|
28
29
|
if not mkdocs_config.exists() and not mkdocs_config_alt.exists():
|
|
29
30
|
raise CommandError(
|
|
30
31
|
"MkDocs configuration file not found. Please create either 'mkdocs.yml' or 'mkdocs.yaml' "
|
|
@@ -34,10 +35,7 @@ class Command(BaseCommand):
|
|
|
34
35
|
try:
|
|
35
36
|
# Generate the model documentation JSON first
|
|
36
37
|
self.stdout.write("Generating model documentation...")
|
|
37
|
-
|
|
38
|
-
call_command(
|
|
39
|
-
"generate_model_docs", "--pretty"
|
|
40
|
-
)
|
|
38
|
+
call_command("generate_model_docs", "--pretty")
|
|
41
39
|
self.stdout.write(self.style.SUCCESS("Model documentation generated."))
|
|
42
40
|
|
|
43
41
|
# Generate the documentation content
|
|
@@ -47,17 +45,7 @@ class Command(BaseCommand):
|
|
|
47
45
|
|
|
48
46
|
# Build the MkDocs site
|
|
49
47
|
self.stdout.write("Building MkDocs site...")
|
|
50
|
-
|
|
51
|
-
["mkdocs", "build", "--clean"],
|
|
52
|
-
check=False,
|
|
53
|
-
cwd=base_dir,
|
|
54
|
-
capture_output=True,
|
|
55
|
-
text=True,
|
|
56
|
-
)
|
|
57
|
-
|
|
58
|
-
if result.returncode != 0:
|
|
59
|
-
raise CommandError(f"MkDocs build failed: {result.stderr}")
|
|
60
|
-
|
|
48
|
+
self._build_mkdocs_site(base_dir, site_dir)
|
|
61
49
|
self.stdout.write(self.style.SUCCESS("Documentation built successfully!"))
|
|
62
50
|
self.stdout.write(f"Site built in: {site_dir}")
|
|
63
51
|
|
|
@@ -65,3 +53,56 @@ class Command(BaseCommand):
|
|
|
65
53
|
raise CommandError(
|
|
66
54
|
"MkDocs not found. Please install it with: pip install mkdocs mkdocs-material"
|
|
67
55
|
) from e
|
|
56
|
+
|
|
57
|
+
def _build_mkdocs_site(self, base_dir: Path, site_dir: Path) -> None:
|
|
58
|
+
"""
|
|
59
|
+
Build the MkDocs site with proper security checks.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
base_dir: The base directory of the Django project
|
|
63
|
+
site_dir: The directory where the site will be built
|
|
64
|
+
|
|
65
|
+
Raises:
|
|
66
|
+
FileNotFoundError: If mkdocs executable is not found
|
|
67
|
+
CommandError: If the build process fails
|
|
68
|
+
"""
|
|
69
|
+
mkdocs_path = shutil.which("mkdocs")
|
|
70
|
+
if not mkdocs_path:
|
|
71
|
+
raise FileNotFoundError("mkdocs executable not found in PATH")
|
|
72
|
+
|
|
73
|
+
mkdocs_path_obj = Path(mkdocs_path)
|
|
74
|
+
if not mkdocs_path_obj.exists() or not mkdocs_path_obj.is_file():
|
|
75
|
+
raise CommandError(f"Invalid mkdocs executable path: {mkdocs_path}")
|
|
76
|
+
|
|
77
|
+
if not base_dir.is_absolute():
|
|
78
|
+
base_dir = base_dir.resolve()
|
|
79
|
+
|
|
80
|
+
if not base_dir.exists():
|
|
81
|
+
raise CommandError(f"Base directory does not exist: {base_dir}")
|
|
82
|
+
|
|
83
|
+
cmd = [
|
|
84
|
+
str(mkdocs_path_obj), # Convert to string for subprocess
|
|
85
|
+
"build",
|
|
86
|
+
"--clean",
|
|
87
|
+
]
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
result = subprocess.run( # noqa S603
|
|
91
|
+
cmd,
|
|
92
|
+
check=True,
|
|
93
|
+
cwd=str(base_dir),
|
|
94
|
+
capture_output=True,
|
|
95
|
+
text=True,
|
|
96
|
+
timeout=300,
|
|
97
|
+
)
|
|
98
|
+
|
|
99
|
+
if result.stdout:
|
|
100
|
+
self.stdout.write(f"MkDocs output: {result.stdout}")
|
|
101
|
+
|
|
102
|
+
except subprocess.TimeoutExpired as e:
|
|
103
|
+
raise CommandError("MkDocs build timed out after 5 minutes") from e
|
|
104
|
+
except subprocess.CalledProcessError as e:
|
|
105
|
+
error_msg = f"MkDocs build failed (exit code {e.returncode})"
|
|
106
|
+
if e.stderr:
|
|
107
|
+
error_msg += f": {e.stderr}"
|
|
108
|
+
raise CommandError(error_msg) from e
|
|
@@ -4,6 +4,7 @@ from pathlib import Path
|
|
|
4
4
|
|
|
5
5
|
from django.core.management.base import BaseCommand
|
|
6
6
|
|
|
7
|
+
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
7
8
|
from drf_to_mkdoc.utils.common import get_schema, load_model_json_data
|
|
8
9
|
from drf_to_mkdoc.utils.endpoint_generator import (
|
|
9
10
|
create_endpoints_index,
|
|
@@ -11,8 +12,6 @@ from drf_to_mkdoc.utils.endpoint_generator import (
|
|
|
11
12
|
parse_endpoints_from_schema,
|
|
12
13
|
)
|
|
13
14
|
from drf_to_mkdoc.utils.model_generator import create_models_index, generate_model_docs
|
|
14
|
-
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
15
|
-
|
|
16
15
|
|
|
17
16
|
|
|
18
17
|
class Command(BaseCommand):
|
|
@@ -1,19 +1,21 @@
|
|
|
1
|
-
from asyncio.log import logger
|
|
2
1
|
import importlib
|
|
3
|
-
import yaml
|
|
4
2
|
import json
|
|
5
3
|
import re
|
|
4
|
+
from asyncio.log import logger
|
|
6
5
|
from functools import lru_cache
|
|
7
6
|
from pathlib import Path
|
|
8
|
-
from typing import Any
|
|
7
|
+
from typing import Any
|
|
9
8
|
|
|
9
|
+
import yaml
|
|
10
10
|
from django.apps import apps
|
|
11
11
|
from django.core.exceptions import AppRegistryNotReady
|
|
12
12
|
from django.urls import resolve
|
|
13
13
|
from django.utils.module_loading import import_string
|
|
14
14
|
from drf_spectacular.generators import SchemaGenerator
|
|
15
|
+
|
|
15
16
|
from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
|
|
16
17
|
|
|
18
|
+
|
|
17
19
|
class SchemaValidationError(Exception):
|
|
18
20
|
"""Custom exception for schema validation errors."""
|
|
19
21
|
|
|
@@ -37,9 +39,10 @@ def substitute_path_params(path: str, parameters: list[dict[str, Any]]) -> str:
|
|
|
37
39
|
django_path = re.sub(r"<path:[^>]+>", "dummy/path", django_path)
|
|
38
40
|
django_path = re.sub(r"<[^:>]+>", "dummy", django_path) # Catch remaining simple params
|
|
39
41
|
|
|
40
|
-
return django_path
|
|
42
|
+
return django_path # noqa: RET504
|
|
43
|
+
|
|
41
44
|
|
|
42
|
-
def load_schema() ->
|
|
45
|
+
def load_schema() -> dict[str, Any] | None:
|
|
43
46
|
"""Load the OpenAPI schema from doc-schema.yaml"""
|
|
44
47
|
schema_file = Path(drf_to_mkdoc_settings.CONFIG_DIR) / "doc-schema.yaml"
|
|
45
48
|
if not schema_file.exists():
|
|
@@ -49,7 +52,7 @@ def load_schema() -> Optional[dict[str, Any]]:
|
|
|
49
52
|
return yaml.safe_load(f)
|
|
50
53
|
|
|
51
54
|
|
|
52
|
-
def load_model_json_data() ->
|
|
55
|
+
def load_model_json_data() -> dict[str, Any] | None:
|
|
53
56
|
"""Load the JSON mapping data for model information"""
|
|
54
57
|
json_file = Path(drf_to_mkdoc_settings.MODEL_DOCS_FILE)
|
|
55
58
|
if not json_file.exists():
|
|
@@ -59,7 +62,7 @@ def load_model_json_data() -> Optional[dict[str, Any]]:
|
|
|
59
62
|
return json.load(f)
|
|
60
63
|
|
|
61
64
|
|
|
62
|
-
def load_doc_config() ->
|
|
65
|
+
def load_doc_config() -> dict[str, Any] | None:
|
|
63
66
|
"""Load the documentation configuration file"""
|
|
64
67
|
config_file = Path(drf_to_mkdoc_settings.DOC_CONFIG_FILE)
|
|
65
68
|
if not config_file.exists():
|
|
@@ -69,7 +72,7 @@ def load_doc_config() -> Optional[dict[str, Any]]:
|
|
|
69
72
|
return json.load(f)
|
|
70
73
|
|
|
71
74
|
|
|
72
|
-
def get_model_docstring(class_name: str) ->
|
|
75
|
+
def get_model_docstring(class_name: str) -> str | None:
|
|
73
76
|
"""Extract docstring from Django model class"""
|
|
74
77
|
try:
|
|
75
78
|
# Check if Django is properly initialized
|
|
@@ -167,6 +170,7 @@ def get_custom_schema():
|
|
|
167
170
|
raise QueryParamTypeError("Invalid queryparam_type")
|
|
168
171
|
return data
|
|
169
172
|
|
|
173
|
+
|
|
170
174
|
def convert_to_django_path(path: str, parameters: list[dict[str, Any]]) -> str:
|
|
171
175
|
"""
|
|
172
176
|
Convert a path with {param} to a Django-style path with <type:param>.
|
|
@@ -193,26 +197,27 @@ def convert_to_django_path(path: str, parameters: list[dict[str, Any]]) -> str:
|
|
|
193
197
|
# Default Django path conversion
|
|
194
198
|
def replacement(match):
|
|
195
199
|
param_name = match.group(1)
|
|
196
|
-
param_info = next((p for p in parameters if p.get(
|
|
197
|
-
param_type = param_info.get(
|
|
198
|
-
param_format = param_info.get(
|
|
199
|
-
|
|
200
|
-
if param_type ==
|
|
201
|
-
converter =
|
|
202
|
-
elif param_type ==
|
|
203
|
-
converter =
|
|
200
|
+
param_info = next((p for p in parameters if p.get("name") == param_name), {})
|
|
201
|
+
param_type = param_info.get("schema", {}).get("type")
|
|
202
|
+
param_format = param_info.get("schema", {}).get("format")
|
|
203
|
+
|
|
204
|
+
if param_type == "integer":
|
|
205
|
+
converter = "int"
|
|
206
|
+
elif param_type == "string" and param_format == "uuid":
|
|
207
|
+
converter = "uuid"
|
|
204
208
|
else:
|
|
205
|
-
converter =
|
|
209
|
+
converter = "str"
|
|
206
210
|
|
|
207
|
-
return f
|
|
211
|
+
return f"<{converter}:{param_name}>"
|
|
208
212
|
|
|
209
|
-
django_path = re.sub(r
|
|
213
|
+
django_path = re.sub(r"{(\w+)}", replacement, path)
|
|
210
214
|
|
|
211
|
-
if not django_path.endswith(
|
|
212
|
-
django_path +=
|
|
215
|
+
if not django_path.endswith("/"):
|
|
216
|
+
django_path += "/"
|
|
213
217
|
|
|
214
218
|
return django_path
|
|
215
219
|
|
|
220
|
+
|
|
216
221
|
@lru_cache
|
|
217
222
|
def get_schema():
|
|
218
223
|
base_schema = SchemaGenerator().get_schema(request=None, public=True)
|
|
@@ -291,7 +296,7 @@ def extract_viewset_from_operation_id(operation_id: str):
|
|
|
291
296
|
else:
|
|
292
297
|
return view_func
|
|
293
298
|
|
|
294
|
-
except Exception
|
|
299
|
+
except Exception:
|
|
295
300
|
logger.error(f"Failed to resolve path {path}")
|
|
296
301
|
|
|
297
302
|
|