drf-to-mkdoc 0.1.5__py3-none-any.whl → 1.0.7__py3-none-any.whl
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/__init__.py +1 -1
- drf_to_mkdoc/apps.py +6 -2
- drf_to_mkdoc/conf/defaults.py +0 -1
- drf_to_mkdoc/conf/settings.py +8 -5
- drf_to_mkdoc/management/commands/build_docs.py +61 -20
- drf_to_mkdoc/management/commands/generate_docs.py +1 -2
- drf_to_mkdoc/management/commands/generate_model_docs.py +37 -7
- drf_to_mkdoc/static/drf-to-mkdoc/javascripts/endpoints-filter.js +189 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/accessibility.css +21 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/animations.css +11 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/badges.css +54 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/base.css +15 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/endpoint-content.css +48 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/endpoints-grid.css +75 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/filter-section.css +209 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/fixes.css +44 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/layout.css +31 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/loading.css +35 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/responsive.css +89 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/sections.css +35 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/stats.css +34 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/tags.css +92 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/theme-toggle.css +30 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/variables.css +30 -0
- drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/extra.css +358 -0
- drf_to_mkdoc/utils/common.py +31 -26
- drf_to_mkdoc/utils/endpoint_generator.py +130 -131
- drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +7 -7
- {drf_to_mkdoc-0.1.5.dist-info → drf_to_mkdoc-1.0.7.dist-info}/METADATA +1 -1
- drf_to_mkdoc-1.0.7.dist-info/RECORD +43 -0
- drf_to_mkdoc-0.1.5.dist-info/RECORD +0 -25
- {drf_to_mkdoc-0.1.5.dist-info → drf_to_mkdoc-1.0.7.dist-info}/WHEEL +0 -0
- {drf_to_mkdoc-0.1.5.dist-info → drf_to_mkdoc-1.0.7.dist-info}/licenses/LICENSE +0 -0
- {drf_to_mkdoc-0.1.5.dist-info → drf_to_mkdoc-1.0.7.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
/* Custom styles for Tabib API Documentation */
|
|
2
|
+
|
|
3
|
+
/* Status badges for HTTP methods */
|
|
4
|
+
.method-badge {
|
|
5
|
+
display: inline-block;
|
|
6
|
+
padding: 2px 8px;
|
|
7
|
+
border-radius: 4px;
|
|
8
|
+
font-size: 0.8em;
|
|
9
|
+
font-weight: bold;
|
|
10
|
+
color: white;
|
|
11
|
+
margin-right: 8px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
.method-get { background-color: #28a745; }
|
|
15
|
+
.method-post { background-color: #007bff; }
|
|
16
|
+
.method-put { background-color: #ffc107; color: #212529; }
|
|
17
|
+
.method-patch { background-color: #6f42c1; }
|
|
18
|
+
.method-delete { background-color: #dc3545; }
|
|
19
|
+
|
|
20
|
+
/* Enhanced code blocks */
|
|
21
|
+
.highlight pre {
|
|
22
|
+
border-left: 4px solid var(--md-primary-fg-color);
|
|
23
|
+
background-color: var(--md-code-bg-color);
|
|
24
|
+
padding: 1rem;
|
|
25
|
+
border-radius: 0.2rem;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/* Model field tables */
|
|
29
|
+
table {
|
|
30
|
+
border-collapse: collapse;
|
|
31
|
+
width: 100%;
|
|
32
|
+
margin: 1rem 0;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
table th {
|
|
36
|
+
background-color: var(--md-primary-fg-color--light);
|
|
37
|
+
color: var(--md-primary-bg-color);
|
|
38
|
+
padding: 0.75rem;
|
|
39
|
+
text-align: left;
|
|
40
|
+
font-weight: 600;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
table td {
|
|
44
|
+
padding: 0.75rem;
|
|
45
|
+
border-bottom: 1px solid var(--md-default-fg-color--lightest);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
table tr:hover {
|
|
49
|
+
background-color: var(--md-accent-fg-color--transparent);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
/* Field and method grids */
|
|
53
|
+
.field-grid, .method-grid {
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
|
56
|
+
gap: 1rem;
|
|
57
|
+
margin: 1rem 0;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.field-item, .method-item {
|
|
61
|
+
background-color: var(--md-default-bg-color);
|
|
62
|
+
border: 1px solid var(--md-default-fg-color--lightest);
|
|
63
|
+
border-radius: 0.2rem;
|
|
64
|
+
padding: 1rem;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.field-item h4, .method-item h4 {
|
|
68
|
+
margin-top: 0;
|
|
69
|
+
color: var(--md-primary-fg-color);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/* API endpoint sections */
|
|
73
|
+
.endpoint-section {
|
|
74
|
+
border-left: 4px solid var(--md-accent-fg-color);
|
|
75
|
+
padding-left: 1rem;
|
|
76
|
+
margin: 2rem 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.endpoint-header {
|
|
80
|
+
display: flex;
|
|
81
|
+
align-items: center;
|
|
82
|
+
margin-bottom: 1rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.endpoint-path {
|
|
86
|
+
font-family: var(--md-code-font);
|
|
87
|
+
background-color: var(--md-code-bg-color);
|
|
88
|
+
padding: 0.2rem 0.5rem;
|
|
89
|
+
border-radius: 0.2rem;
|
|
90
|
+
margin-left: 0.5rem;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/* Navigation enhancements */
|
|
94
|
+
.md-nav__item--active > .md-nav__link {
|
|
95
|
+
font-weight: 600;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/* Admonition customizations */
|
|
99
|
+
.admonition.note {
|
|
100
|
+
border-left-color: var(--md-primary-fg-color);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
.admonition.tip {
|
|
104
|
+
border-left-color: #00c853;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.admonition.warning {
|
|
108
|
+
border-left-color: #ff9800;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.admonition.danger {
|
|
112
|
+
border-left-color: #f44336;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/* Search result enhancements */
|
|
116
|
+
.md-search-result__meta {
|
|
117
|
+
color: var(--md-default-fg-color--light);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/* Responsive design improvements */
|
|
121
|
+
@media screen and (max-width: 768px) {
|
|
122
|
+
.field-grid, .method-grid {
|
|
123
|
+
grid-template-columns: 1fr;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
.endpoint-header {
|
|
127
|
+
flex-direction: column;
|
|
128
|
+
align-items: flex-start;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.endpoint-path {
|
|
132
|
+
margin-left: 0;
|
|
133
|
+
margin-top: 0.5rem;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/* Code syntax highlighting enhancements */
|
|
138
|
+
.codehilite .k { color: #0066cc; } /* Keywords */
|
|
139
|
+
.codehilite .s { color: #009900; } /* Strings */
|
|
140
|
+
.codehilite .c { color: #999999; } /* Comments */
|
|
141
|
+
.codehilite .n { color: #333333; } /* Names */
|
|
142
|
+
.codehilite .o { color: #666666; } /* Operators */
|
|
143
|
+
|
|
144
|
+
/* Dark mode adjustments */
|
|
145
|
+
[data-md-color-scheme="slate"] .field-item,
|
|
146
|
+
[data-md-color-scheme="slate"] .method-item {
|
|
147
|
+
background-color: var(--md-code-bg-color);
|
|
148
|
+
border-color: var(--md-default-fg-color--lightest);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
[data-md-color-scheme="slate"] table th {
|
|
152
|
+
background-color: var(--md-primary-fg-color);
|
|
153
|
+
color: var(--md-primary-bg-color);
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/* Custom icons for different sections */
|
|
157
|
+
.md-nav__item[data-md-level="1"] > .md-nav__link[href*="models"] {
|
|
158
|
+
position: relative;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
.md-nav__item[data-md-level="1"] > .md-nav__link[href*="models"]::before {
|
|
162
|
+
content: "🗃️";
|
|
163
|
+
margin-right: 0.5rem;
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
.md-nav__item[data-md-level="1"] > .md-nav__link[href*="endpoints"] {
|
|
167
|
+
position: relative;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
.md-nav__item[data-md-level="1"] > .md-nav__link[href*="endpoints"]::before {
|
|
171
|
+
content: "🔗";
|
|
172
|
+
margin-right: 0.5rem;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/* Print styles */
|
|
176
|
+
@media print {
|
|
177
|
+
.md-header, .md-sidebar, .md-footer {
|
|
178
|
+
display: none;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
.md-content {
|
|
182
|
+
margin: 0;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
.highlight pre {
|
|
186
|
+
border: 1px solid #ccc;
|
|
187
|
+
page-break-inside: avoid;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/* =================== DJANGO MODELS CARD LAYOUT =================== */
|
|
192
|
+
|
|
193
|
+
/* Models container */
|
|
194
|
+
.models-container {
|
|
195
|
+
max-width: 100%;
|
|
196
|
+
margin: 0 auto;
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
/* App description styling */
|
|
200
|
+
.app-description {
|
|
201
|
+
font-size: 1rem;
|
|
202
|
+
color: var(--md-default-fg-color--light);
|
|
203
|
+
margin-bottom: 1.5rem;
|
|
204
|
+
padding: 0.5rem 0;
|
|
205
|
+
border-bottom: 1px solid var(--md-default-fg-color--lightest);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
/* Model cards grid */
|
|
209
|
+
.model-cards {
|
|
210
|
+
display: grid;
|
|
211
|
+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
|
|
212
|
+
gap: 1.5rem;
|
|
213
|
+
margin-bottom: 3rem;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/* Individual model card */
|
|
217
|
+
.model-card {
|
|
218
|
+
background: var(--md-default-bg-color);
|
|
219
|
+
border: 1px solid var(--md-default-fg-color--lightest);
|
|
220
|
+
border-radius: 8px;
|
|
221
|
+
padding: 1.5rem;
|
|
222
|
+
transition: all 0.3s ease;
|
|
223
|
+
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
|
224
|
+
position: relative;
|
|
225
|
+
overflow: hidden;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
.model-card:hover {
|
|
229
|
+
transform: translateY(-4px);
|
|
230
|
+
box-shadow: 0 8px 16px rgba(0, 0, 0, 0.15);
|
|
231
|
+
border-color: var(--md-primary-fg-color);
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.model-card::before {
|
|
235
|
+
content: '';
|
|
236
|
+
position: absolute;
|
|
237
|
+
top: 0;
|
|
238
|
+
left: 0;
|
|
239
|
+
right: 0;
|
|
240
|
+
height: 4px;
|
|
241
|
+
background: linear-gradient(90deg, var(--md-primary-fg-color), var(--md-accent-fg-color));
|
|
242
|
+
opacity: 0;
|
|
243
|
+
transition: opacity 0.3s ease;
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
.model-card:hover::before {
|
|
247
|
+
opacity: 1;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/* Model header */
|
|
251
|
+
.model-header {
|
|
252
|
+
display: flex;
|
|
253
|
+
justify-content: space-between;
|
|
254
|
+
align-items: center;
|
|
255
|
+
margin-bottom: 0.5rem;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
.model-header h3 {
|
|
259
|
+
margin: 0;
|
|
260
|
+
font-size: 1.25rem;
|
|
261
|
+
font-weight: 600;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
.model-header h3 a {
|
|
265
|
+
color: var(--md-default-fg-color);
|
|
266
|
+
text-decoration: none;
|
|
267
|
+
transition: color 0.3s ease;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.model-header h3 a:hover {
|
|
271
|
+
color: var(--md-primary-fg-color);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/* Model badge */
|
|
275
|
+
.model-badge {
|
|
276
|
+
display: inline-block;
|
|
277
|
+
padding: 0.25rem 0.75rem;
|
|
278
|
+
background: var(--md-primary-fg-color);
|
|
279
|
+
color: var(--md-primary-bg-color);
|
|
280
|
+
border-radius: 20px;
|
|
281
|
+
font-size: 0.75rem;
|
|
282
|
+
font-weight: 600;
|
|
283
|
+
text-transform: uppercase;
|
|
284
|
+
letter-spacing: 0.5px;
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
/* Dark mode adjustments for model cards */
|
|
288
|
+
[data-md-color-scheme="slate"] .model-card {
|
|
289
|
+
background: var(--md-code-bg-color);
|
|
290
|
+
border-color: var(--md-default-fg-color--lightest);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
[data-md-color-scheme="slate"] .model-card:hover {
|
|
294
|
+
border-color: var(--md-primary-fg-color);
|
|
295
|
+
box-shadow: 0 8px 16px rgba(255, 255, 255, 0.1);
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
[data-md-color-scheme="slate"] .app-description {
|
|
299
|
+
color: var(--md-default-fg-color--light);
|
|
300
|
+
border-color: var(--md-default-fg-color--lightest);
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/* Responsive adjustments for model cards */
|
|
304
|
+
@media screen and (max-width: 768px) {
|
|
305
|
+
.model-cards {
|
|
306
|
+
grid-template-columns: 1fr;
|
|
307
|
+
gap: 1rem;
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
.model-card {
|
|
311
|
+
padding: 1rem;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
.model-header h3 {
|
|
315
|
+
font-size: 1.1rem;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
.model-badge {
|
|
319
|
+
font-size: 0.7rem;
|
|
320
|
+
padding: 0.2rem 0.6rem;
|
|
321
|
+
}
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
@media screen and (max-width: 480px) {
|
|
325
|
+
.model-header {
|
|
326
|
+
flex-direction: column;
|
|
327
|
+
align-items: flex-start;
|
|
328
|
+
gap: 0.5rem;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
.model-badge {
|
|
332
|
+
align-self: flex-start;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
/* Animation for cards appearing */
|
|
337
|
+
@keyframes fadeInUp {
|
|
338
|
+
from {
|
|
339
|
+
opacity: 0;
|
|
340
|
+
transform: translateY(20px);
|
|
341
|
+
}
|
|
342
|
+
to {
|
|
343
|
+
opacity: 1;
|
|
344
|
+
transform: translateY(0);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
.model-card {
|
|
349
|
+
animation: fadeInUp 0.6s ease-out;
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
/* Stagger animation for multiple cards */
|
|
353
|
+
.model-card:nth-child(1) { animation-delay: 0.1s; }
|
|
354
|
+
.model-card:nth-child(2) { animation-delay: 0.2s; }
|
|
355
|
+
.model-card:nth-child(3) { animation-delay: 0.3s; }
|
|
356
|
+
.model-card:nth-child(4) { animation-delay: 0.4s; }
|
|
357
|
+
.model-card:nth-child(5) { animation-delay: 0.5s; }
|
|
358
|
+
.model-card:nth-child(6) { animation-delay: 0.6s; }
|
drf_to_mkdoc/utils/common.py
CHANGED
|
@@ -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,19 +170,20 @@ 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>.
|
|
173
|
-
If
|
|
177
|
+
If PATH_PARAM_SUBSTITUTOR is set, use that function instead.
|
|
174
178
|
"""
|
|
175
179
|
function = None
|
|
176
|
-
func_path = getattr(drf_to_mkdoc_settings, "
|
|
180
|
+
func_path = getattr(drf_to_mkdoc_settings, "PATH_PARAM_SUBSTITUTOR", None)
|
|
177
181
|
|
|
178
182
|
if func_path:
|
|
179
183
|
try:
|
|
180
184
|
function = import_string(func_path)
|
|
181
185
|
except ImportError:
|
|
182
|
-
logger.warning("
|
|
186
|
+
logger.warning("PATH_PARAM_SUBSTITUTOR is not a valid import path")
|
|
183
187
|
|
|
184
188
|
# If custom function exists and returns a valid value, use it
|
|
185
189
|
if callable(function):
|
|
@@ -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,8 +296,8 @@ def extract_viewset_from_operation_id(operation_id: str):
|
|
|
291
296
|
else:
|
|
292
297
|
return view_func
|
|
293
298
|
|
|
294
|
-
except Exception
|
|
295
|
-
|
|
299
|
+
except Exception:
|
|
300
|
+
logger.error(f"Failed to resolve path {path}")
|
|
296
301
|
|
|
297
302
|
|
|
298
303
|
def extract_viewset_name_from_operation_id(operation_id: str):
|