drf-to-mkdoc 0.2.2__py3-none-any.whl → 0.2.3__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.

Files changed (35) hide show
  1. drf_to_mkdoc/conf/defaults.py +1 -0
  2. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/form-manager.js +172 -0
  3. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/main.js +22 -0
  4. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/modal.js +79 -0
  5. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/request-executor.js +111 -0
  6. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/suggestions.js +216 -0
  7. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out/tabs.js +34 -0
  8. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/buttons.css +71 -0
  9. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/fab.css +47 -0
  10. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/form.css +124 -0
  11. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/key-value.css +161 -0
  12. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/main.css +57 -0
  13. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/modal.css +112 -0
  14. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/response.css +158 -0
  15. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/tabs.css +62 -0
  16. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/try-out/variables.css +38 -0
  17. drf_to_mkdoc/templates/endpoints/detail/base.html +3 -1
  18. drf_to_mkdoc/templates/endpoints/detail/query_parameters.html +1 -8
  19. drf_to_mkdoc/templates/endpoints/detail/responses.html +4 -4
  20. drf_to_mkdoc/templates/try-out/fab.html +4 -0
  21. drf_to_mkdoc/templates/try-out/form.html +113 -0
  22. drf_to_mkdoc/templates/try-out/main.html +4 -0
  23. drf_to_mkdoc/templates/try-out/modal.html +14 -0
  24. drf_to_mkdoc/templates/try-out/response-modal.html +20 -0
  25. drf_to_mkdoc/templatetags/custom_filters.py +33 -1
  26. drf_to_mkdoc/utils/commons/schema_utils.py +5 -14
  27. drf_to_mkdoc/utils/endpoint_detail_generator.py +140 -21
  28. drf_to_mkdoc/utils/extractors/query_parameter_extractors.py +0 -15
  29. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/METADATA +1 -1
  30. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/RECORD +33 -15
  31. drf_to_mkdoc/static/drf-to-mkdoc/javascripts/try-out-sidebar.js +0 -879
  32. drf_to_mkdoc/static/drf-to-mkdoc/stylesheets/endpoints/try-out-sidebar.css +0 -728
  33. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/WHEEL +0 -0
  34. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/licenses/LICENSE +0 -0
  35. {drf_to_mkdoc-0.2.2.dist-info → drf_to_mkdoc-0.2.3.dist-info}/top_level.txt +0 -0
@@ -0,0 +1,158 @@
1
+ /* Response Modal */
2
+ .response-modal {
3
+ position: fixed;
4
+ top: 0;
5
+ left: 0;
6
+ width: 100%;
7
+ height: 100%;
8
+ z-index: var(--try-out-z-response);
9
+ display: none;
10
+ align-items: center;
11
+ justify-content: center;
12
+ padding: var(--try-out-spacing-lg);
13
+ box-sizing: border-box;
14
+ }
15
+
16
+ .response-modal .modal-header {
17
+ padding: var(--try-out-spacing-lg) var(--try-out-spacing-xl);
18
+ background: linear-gradient(135deg, var(--try-out-primary), #1565c0);
19
+ color: white;
20
+ display: flex;
21
+ align-items: center;
22
+ gap: var(--try-out-spacing);
23
+ flex-shrink: 0;
24
+ position: relative;
25
+ }
26
+
27
+ .response-modal .modal-header h3 {
28
+ margin: 0;
29
+ font-size: var(--try-out-font-lg);
30
+ font-weight: 600;
31
+ flex-grow: 1;
32
+ }
33
+
34
+ .response-modal .modal-close {
35
+ background: none;
36
+ border: none;
37
+ color: white;
38
+ cursor: pointer;
39
+ padding: var(--try-out-spacing-sm);
40
+ font-size: var(--try-out-font-lg);
41
+ line-height: 1;
42
+ border-radius: 50%;
43
+ width: 28px;
44
+ height: 28px;
45
+ display: flex;
46
+ align-items: center;
47
+ justify-content: center;
48
+ position: absolute;
49
+ right: var(--try-out-spacing);
50
+ top: 50%;
51
+ transform: translateY(-50%);
52
+ }
53
+
54
+ .response-modal .modal-close:hover {
55
+ background-color: rgba(255, 255, 255, 0.1);
56
+ }
57
+
58
+ .response-modal .modal-body {
59
+ padding: var(--try-out-spacing-xl);
60
+ overflow-y: auto;
61
+ flex: 1;
62
+ }
63
+
64
+ .response-modal.show {
65
+ display: flex;
66
+ }
67
+
68
+ .response-modal .modal-content {
69
+ position: relative;
70
+ width: 100%;
71
+ max-width: 700px;
72
+ max-height: 85vh;
73
+ background-color: var(--try-out-bg);
74
+ border-radius: var(--try-out-border-radius-lg);
75
+ box-shadow: 0 8px 32px var(--try-out-shadow-strong);
76
+ overflow: hidden;
77
+ z-index: 1;
78
+ display: flex;
79
+ flex-direction: column;
80
+ }
81
+
82
+ .response-modal .response-header {
83
+ margin-bottom: var(--try-out-spacing-lg);
84
+ padding: var(--try-out-spacing);
85
+ border-radius: var(--try-out-border-radius);
86
+ background-color: var(--try-out-surface);
87
+ display: flex;
88
+ align-items: center;
89
+ gap: var(--try-out-spacing);
90
+ }
91
+
92
+ .response-modal .status-badge {
93
+ padding: var(--try-out-spacing-sm) var(--try-out-spacing);
94
+ border-radius: var(--try-out-border-radius);
95
+ font-size: var(--try-out-font-sm);
96
+ font-weight: 600;
97
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
98
+ }
99
+
100
+ .response-modal .status-200 {
101
+ background-color: var(--try-out-success);
102
+ color: white;
103
+ }
104
+
105
+ .response-modal .status-300 {
106
+ background-color: var(--try-out-info);
107
+ color: white;
108
+ }
109
+
110
+ .response-modal .status-400 {
111
+ background-color: var(--try-out-warning);
112
+ color: #212529;
113
+ }
114
+
115
+ .response-modal .status-500 {
116
+ background-color: var(--try-out-danger);
117
+ color: white;
118
+ }
119
+
120
+ .response-modal .response-body {
121
+ background-color: var(--try-out-surface);
122
+ padding: var(--try-out-spacing-lg);
123
+ border-radius: var(--try-out-border-radius);
124
+ overflow: auto;
125
+ font-family: 'Monaco', 'Menlo', 'Ubuntu Mono', monospace;
126
+ white-space: pre-wrap;
127
+ font-size: var(--try-out-font-sm);
128
+ line-height: var(--try-out-line-height);
129
+ max-height: 300px;
130
+ border: 1px solid var(--try-out-border);
131
+ flex: 1;
132
+ }
133
+
134
+ .response-modal .response-info {
135
+ display: flex;
136
+ align-items: center;
137
+ gap: var(--try-out-spacing);
138
+ font-size: var(--try-out-font-base);
139
+ color: var(--try-out-text);
140
+ font-weight: 500;
141
+ }
142
+
143
+ /* Mobile Response Modal */
144
+ @media screen and (max-width: 768px) {
145
+ .response-modal {
146
+ padding: var(--try-out-spacing-sm);
147
+ }
148
+
149
+ .response-modal .modal-content {
150
+ max-width: none;
151
+ max-height: 90vh;
152
+ }
153
+
154
+ .response-modal .response-body {
155
+ font-size: 12px;
156
+ max-height: 250px;
157
+ }
158
+ }
@@ -0,0 +1,62 @@
1
+ /* Tabs */
2
+ .tabs {
3
+ display: flex;
4
+ gap: 0;
5
+ margin-bottom: var(--try-out-spacing-lg);
6
+ border: 1px solid var(--try-out-border);
7
+ border-radius: var(--try-out-border-radius);
8
+ overflow: hidden;
9
+ background-color: var(--try-out-surface);
10
+ }
11
+
12
+ .tab {
13
+ flex: 1;
14
+ padding: var(--try-out-spacing) var(--try-out-spacing-lg);
15
+ border: none;
16
+ background: transparent;
17
+ color: var(--try-out-text-light);
18
+ cursor: pointer;
19
+ font-size: var(--try-out-font-base);
20
+ font-weight: 500;
21
+ position: relative;
22
+ transition: var(--try-out-transition);
23
+ border-right: 1px solid var(--try-out-border);
24
+ }
25
+
26
+ .tab:last-child {
27
+ border-right: none;
28
+ }
29
+
30
+ .tab:hover {
31
+ background-color: rgba(25, 118, 210, 0.05);
32
+ color: var(--try-out-text);
33
+ }
34
+
35
+ .tab.active {
36
+ background-color: var(--try-out-primary);
37
+ color: white;
38
+ }
39
+
40
+ .tab-content {
41
+ display: none;
42
+ }
43
+
44
+ .tab-content.active {
45
+ display: block;
46
+ }
47
+
48
+ /* Mobile Tabs */
49
+ @media screen and (max-width: 768px) {
50
+ .tabs {
51
+ flex-direction: column;
52
+ }
53
+
54
+ .tab {
55
+ border-right: none;
56
+ border-bottom: 1px solid var(--try-out-border);
57
+ }
58
+
59
+ .tab:last-child {
60
+ border-bottom: none;
61
+ }
62
+ }
@@ -0,0 +1,38 @@
1
+ :root {
2
+ --try-out-primary: #1976d2;
3
+ --try-out-primary-hover: #1565c0;
4
+ --try-out-success: #28a745;
5
+ --try-out-success-hover: #218838;
6
+ --try-out-danger: #dc3545;
7
+ --try-out-danger-hover: #c82333;
8
+ --try-out-warning: #ffc107;
9
+ --try-out-info: #17a2b8;
10
+
11
+ --try-out-bg: #ffffff;
12
+ --try-out-surface: #f8f9fa;
13
+ --try-out-border: #e1e5e9;
14
+ --try-out-text: #333333;
15
+ --try-out-text-light: #666666;
16
+ --try-out-text-lighter: #999999;
17
+ --try-out-shadow: rgba(0, 0, 0, 0.1);
18
+ --try-out-shadow-strong: rgba(0, 0, 0, 0.2);
19
+
20
+ --try-out-border-radius: 4px;
21
+ --try-out-border-radius-lg: 6px;
22
+ --try-out-spacing-xs: 0.2rem;
23
+ --try-out-spacing-sm: 0.4rem;
24
+ --try-out-spacing: 0.6rem;
25
+ --try-out-spacing-lg: 0.8rem;
26
+ --try-out-spacing-xl: 1.2rem;
27
+ --try-out-spacing-xxl: 1.6rem;
28
+
29
+ --try-out-font-sm: 0.75rem;
30
+ --try-out-font-base: 0.8rem;
31
+ --try-out-font-lg: 0.9rem;
32
+ --try-out-line-height: 1.4;
33
+
34
+ --try-out-transition: all 0.2s ease;
35
+ --try-out-z-modal: 1000;
36
+ --try-out-z-response: 1100;
37
+ --try-out-z-fab: 100;
38
+ }
@@ -30,4 +30,6 @@
30
30
  {% include "endpoints/detail/path_parameters.html" %}
31
31
  {% include "endpoints/detail/query_parameters.html" %}
32
32
  {% include "endpoints/detail/request_body.html" %}
33
- {% include "endpoints/detail/responses.html" %}
33
+ {% include "endpoints/detail/responses.html" %}
34
+
35
+ {% include 'try-out/main.html' %}
@@ -2,7 +2,7 @@
2
2
  Check if any query parameter fields have content
3
3
  {% endcomment %}
4
4
 
5
- {% if query_parameters.filter_fields or query_parameters.search_fields or query_parameters.ordering_fields or query_parameters.filter_backends or query_parameters.pagination_fields %}
5
+ {% if query_parameters.filter_fields or query_parameters.search_fields or query_parameters.ordering_fields or query_parameters.pagination_fields %}
6
6
  ## Query Parameters
7
7
 
8
8
  {% if query_parameters.filter_fields %}
@@ -26,13 +26,6 @@ Check if any query parameter fields have content
26
26
  {% endfor %}
27
27
  {% endif %}
28
28
 
29
- {% if query_parameters.filter_backends %}
30
- ### Filter Backends
31
- {% for backend in query_parameters.filter_backends %}
32
- - `{{ backend }}`
33
- {% endfor %}
34
- {% endif %}
35
-
36
29
  {% if query_parameters.pagination_fields %}
37
30
  ### Pagination Fields
38
31
  {% for field in query_parameters.pagination_fields %}
@@ -10,9 +10,9 @@
10
10
  {{ response.description }}
11
11
  {% endif %}
12
12
 
13
- {% if response.example %}
14
- {{ response.example|format_json }}
15
- {% endif %}
13
+ {% for example in response.examples %}
14
+ {{ example|format_json }}
15
+ {% endfor %}
16
16
 
17
17
  {% endfor %}
18
- {% endif %}
18
+ {% endif %}
@@ -0,0 +1,4 @@
1
+ <!-- Try Out Floating Action Button -->
2
+ <button class="try-out-fab" role="button" tabindex="0" aria-label="Open Try It Out" onclick="TryOutSidebar.openTryOut()">
3
+ <span>🚀</span>
4
+ </button>
@@ -0,0 +1,113 @@
1
+ {% load custom_filters %}
2
+
3
+ <div class="try-out-form" data-method="{{ method }}">
4
+ <!-- Base URL Section -->
5
+ <div class="base-url-section">
6
+ <label for="baseUrl">Request URL</label>
7
+ <div class="url-display">
8
+ <input type="text" id="baseUrl" class="base-url-input" value="http://localhost:8000" placeholder="https://api.example.com">
9
+ <span class="path-display">{{ path }}</span>
10
+ </div>
11
+ </div>
12
+
13
+ <!-- Tabs -->
14
+ <div class="tabs">
15
+ <button class="tab active" data-tab="parameters">Parameters</button>
16
+ <button class="tab" data-tab="headers">Headers</button>
17
+ {% if method|upper in "POST,PUT,PATCH" %}
18
+ <button class="tab" data-tab="body">Request Body</button>
19
+ {% endif %}
20
+ </div>
21
+
22
+ <!-- Parameters Tab -->
23
+ <div class="tab-content active" id="parametersTab">
24
+ {% if path_params %}
25
+ <div class="form-group">
26
+ <label class="form-label">Path Parameters</label>
27
+ <div class="kv-container" id="pathParams">
28
+ {% for param in path_params %}
29
+ <div class="kv-item">
30
+ <label class="param-label{% if param.required %} required{% endif %}">{{ param.name }}</label>
31
+ <input type="text"
32
+ placeholder="Enter {{ param.name }} value"
33
+ data-param="{{ param.name }}"
34
+ {% if param.required %}required{% endif %}>
35
+ <div class="error-message"></div>
36
+ </div>
37
+ {% endfor %}
38
+ </div>
39
+ </div>
40
+ {% endif %}
41
+
42
+ <div class="form-group">
43
+ <label class="form-label">Query Parameters</label>
44
+ <div class="kv-container" id="queryParams">
45
+ <div class="kv-item">
46
+ <input type="text" placeholder="Parameter name">
47
+ <input type="text" placeholder="Parameter value">
48
+ <button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
49
+ </div>
50
+ </div>
51
+ <button class="add-btn" onclick="TryOutSidebar.addQueryParam()">
52
+ <span>+</span> Add Parameter
53
+ </button>
54
+ </div>
55
+ </div>
56
+
57
+ <!-- Headers Tab -->
58
+ <div class="tab-content" id="headersTab">
59
+ <div class="form-group">
60
+ <label class="form-label">Request Headers</label>
61
+ <div class="kv-container" id="requestHeaders">
62
+ <div class="kv-item">
63
+ <input type="text" value="Content-Type">
64
+ <input type="text" value="application/json">
65
+ <button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
66
+ </div>
67
+ <div class="kv-item">
68
+ <input type="text" value="Authorization">
69
+ <input type="text" placeholder="Bearer your-token">
70
+ <button class="remove-btn" onclick="TryOutSidebar.removeKvItem(this)">✕</button>
71
+ </div>
72
+ </div>
73
+ <button class="add-btn" onclick="TryOutSidebar.addHeader()">
74
+ <span>+</span> Add Header
75
+ </button>
76
+ </div>
77
+ </div>
78
+
79
+ <!-- Request Body Tab -->
80
+ {% if method|upper in "POST,PUT,PATCH" %}
81
+ <div class="tab-content" id="bodyTab">
82
+ <div class="form-group">
83
+ <label class="form-label">Request Body</label>
84
+ <textarea id="requestBody"
85
+ class="form-input form-textarea"
86
+ placeholder="Enter JSON request body..."
87
+ rows="8">{% if request_example %}{{ request_example|extract_json_from_markdown }}{% endif %}</textarea>
88
+ </div>
89
+ </div>
90
+ {% endif %}
91
+
92
+ <!-- Execute Button -->
93
+ <button class="execute-btn" id="executeBtn" onclick="executeRequest()">
94
+ <span>▶</span> Execute Request
95
+ </button>
96
+ </div>
97
+
98
+ <script>
99
+ // Pass query parameters data to JavaScript
100
+ window.queryParametersData = {
101
+ {% if query_parameters %}
102
+ filter_fields: {{ query_parameters.filter_fields|default:"[]"|safe }},
103
+ search_fields: {{ query_parameters.search_fields|default:"[]"|safe }},
104
+ ordering_fields: {{ query_parameters.ordering_fields|default:"[]"|safe }},
105
+ pagination_fields: {{ query_parameters.pagination_fields|default:"[]"|safe }}
106
+ {% else %}
107
+ filter_fields: [],
108
+ search_fields: [],
109
+ ordering_fields: [],
110
+ pagination_fields: []
111
+ {% endif %}
112
+ };
113
+ </script>
@@ -0,0 +1,4 @@
1
+ <!-- Try Out Main Component -->
2
+ {% include 'try-out/fab.html' %}
3
+ {% include 'try-out/modal.html' %}
4
+ {% include 'try-out/response-modal.html' %}
@@ -0,0 +1,14 @@
1
+ <!-- Try Out Modal -->
2
+ <div id="tryOutModal" class="try-out-modal" role="dialog" aria-modal="true" aria-label="Try It Out">
3
+ <div class="modal-overlay" onclick="TryOutSidebar.closeTryOut()"></div>
4
+ <div class="modal-content">
5
+ <div class="modal-header">
6
+ <span>🚀</span>
7
+ <h3>Try It Out</h3>
8
+ <button class="modal-close" aria-label="Close" onclick="TryOutSidebar.closeTryOut()">✕</button>
9
+ </div>
10
+ <div class="modal-body">
11
+ {% include 'try-out/form.html' %}
12
+ </div>
13
+ </div>
14
+ </div>
@@ -0,0 +1,20 @@
1
+ <!-- Response Modal -->
2
+ <div id="responseModal" class="response-modal" role="dialog" aria-modal="true" aria-label="API Response">
3
+ <div class="modal-overlay" onclick="TryOutSidebar.closeResponseModal()"></div>
4
+ <div class="modal-content">
5
+ <div class="modal-header">
6
+ <h3>API Response</h3>
7
+ <button class="modal-close" aria-label="Close" onclick="TryOutSidebar.closeResponseModal()">✕</button>
8
+ </div>
9
+ <div class="modal-body">
10
+ <div class="response-header">
11
+ <div class="response-info">
12
+ <span>Status:</span>
13
+ <span class="status-badge" id="modalStatusBadge"></span>
14
+ </div>
15
+ <div class="response-info" id="responseInfo"></div>
16
+ </div>
17
+ <div class="response-body" id="modalResponseBody"></div>
18
+ </div>
19
+ </div>
20
+ </div>
@@ -1,5 +1,6 @@
1
1
  import html
2
2
  import json
3
+ import re
3
4
 
4
5
  from django import template
5
6
  from django.templatetags.static import static as django_static
@@ -113,4 +114,35 @@ def format_json(value):
113
114
  elif isinstance(value, dict | list):
114
115
  value = json.dumps(value, indent=2)
115
116
 
116
- return mark_safe(value) # noqa: S308
117
+ return mark_safe(f"```json\n{value}\n```") # noqa: S308
118
+
119
+
120
+ @register.filter
121
+ def extract_json_from_markdown(value):
122
+ """Extract JSON content from markdown code blocks"""
123
+ if not isinstance(value, str):
124
+ return ""
125
+
126
+ # Look for ```json code blocks
127
+
128
+ json_pattern = r"```json\s*\n(.*?)\n```"
129
+ matches = re.findall(json_pattern, value, re.DOTALL)
130
+
131
+ if matches:
132
+ return matches[0].strip()
133
+
134
+ # Fallback: look for any code block
135
+ code_pattern = r"```\s*\n(.*?)\n```"
136
+ matches = re.findall(code_pattern, value, re.DOTALL)
137
+
138
+ if matches:
139
+ content = matches[0].strip()
140
+ # Try to validate if it's JSON
141
+ try:
142
+ json.loads(content)
143
+ except (json.JSONDecodeError, TypeError):
144
+ pass
145
+ else:
146
+ return content
147
+
148
+ return ""
@@ -1,8 +1,9 @@
1
1
  import json
2
+ from copy import deepcopy
3
+ from functools import lru_cache
2
4
  from pathlib import Path
3
5
  from typing import Any
4
6
 
5
- import yaml
6
7
  from drf_spectacular.generators import SchemaGenerator
7
8
 
8
9
  from drf_to_mkdoc.conf.settings import drf_to_mkdoc_settings
@@ -21,16 +22,6 @@ class QueryParamTypeError(Exception):
21
22
  pass
22
23
 
23
24
 
24
- def load_schema() -> dict[str, Any] | None:
25
- """Load the OpenAPI schema from doc-schema.yaml"""
26
- schema_file = Path(drf_to_mkdoc_settings.CONFIG_DIR) / "doc-schema.yaml"
27
- if not schema_file.exists():
28
- return None
29
-
30
- with schema_file.open(encoding="utf-8") as f:
31
- return yaml.safe_load(f)
32
-
33
-
34
25
  def get_custom_schema():
35
26
  custom_schema_data = load_json_data(
36
27
  drf_to_mkdoc_settings.CUSTOM_SCHEMA_FILE, raise_not_found=False
@@ -56,7 +47,6 @@ def get_custom_schema():
56
47
  "search_fields",
57
48
  "filter_fields",
58
49
  "ordering_fields",
59
- "filter_backends",
60
50
  "pagination_fields",
61
51
  }
62
52
  ):
@@ -153,16 +143,17 @@ def _apply_custom_overrides(
153
143
  target_schema[key] = custom_value
154
144
 
155
145
 
146
+ @lru_cache(maxsize=1)
156
147
  def get_schema():
157
148
  base_schema = SchemaGenerator().get_schema(request=None, public=True)
158
149
  custom_data = get_custom_schema()
159
150
  if not custom_data:
160
- return base_schema
151
+ return deepcopy(base_schema)
161
152
 
162
153
  operation_map = _build_operation_map(base_schema)
163
154
  _apply_custom_overrides(base_schema, operation_map, custom_data)
164
155
 
165
- return base_schema
156
+ return deepcopy(base_schema)
166
157
 
167
158
 
168
159
  class OperationExtractor: