Skip to content

Commit b9d3272

Browse files
committed
extra - rename to Cull & Reduce
1 parent b1e9049 commit b9d3272

File tree

6 files changed

+99
-56
lines changed

6 files changed

+99
-56
lines changed

aiopenapi3/extra.py

Lines changed: 43 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,19 @@
11
from re import Pattern
2-
from typing import Dict, List, Union, Tuple
2+
from typing import Dict, List, Union
33
import logging
44
import re
55

66
from .plugin import Document, Init
77

8-
class DocumentReduced(Document):
8+
9+
class Reduce(Document, Init):
910
log = logging.getLogger("aiopenapi3.extra.Reduced")
1011

1112
def __init__(self, operations: Dict[Union[str, Pattern], List[Union[str, Pattern]]]):
12-
self.operations = operations
13+
self.operations: List[Union[str, Pattern]] = operations
1314
super().__init__()
14-
15-
def _reduced_paths(self, ctx: "Document.Context") -> "Document.Context":
15+
16+
def _reduced_paths(self, ctx: "Document.Context") -> dict:
1617
return {
1718
key: {
1819
operation_key: operation_value
@@ -35,7 +36,43 @@ def _reduced_paths(self, ctx: "Document.Context") -> "Document.Context":
3536
}.items()
3637
}
3738

38-
class Culled(DocumentReduced):
39+
def parsed(self, ctx: "Document.Context") -> "Document.Context":
40+
"""Parse the given context."""
41+
ctx.document["paths"] = self._reduced_paths(ctx)
42+
return ctx
43+
44+
def paths(self, ctx: "Init.Context") -> "Init.Context":
45+
"""Clear the paths of the context."""
46+
ctx.paths = None
47+
return ctx
48+
49+
def initialized(self, ctx: "Init.Context") -> "Init.Context":
50+
"""Process the initialized context."""
51+
for name, parameter in list(ctx.initialized.components.parameters.items()):
52+
if parameter.schema_._model_type is None:
53+
del ctx.initialized.components.parameters[name]
54+
break
55+
56+
for name, schema in list(ctx.initialized.components.schemas.items()):
57+
if schema._model_type is None:
58+
del ctx.initialized.components.schemas[name]
59+
break
60+
61+
for name, response in list(ctx.initialized.components.responses.items()):
62+
for k, v in response.content.items():
63+
if v.schema_._model_type is None:
64+
del ctx.initialized.components.responses[name]
65+
break
66+
67+
for name, requestBody in list(ctx.initialized.components.requestBodies.items()):
68+
for k, v in requestBody.content.items():
69+
if v.schema_._model_type is None:
70+
del ctx.initialized.components.requestBodies[name]
71+
break
72+
return ctx
73+
74+
75+
class Cull(Reduce):
3976
@staticmethod
4077
def _extract_references(data, root=None):
4178
"""
@@ -104,42 +141,3 @@ def parsed(self, ctx: "Document.Context") -> "Document.Context":
104141

105142
ctx.document = document
106143
return ctx
107-
108-
class LazyLoaded(DocumentReduced, Init):
109-
def parsed(self, ctx: "Document.Context") -> "Document.Context":
110-
"""Parse the given context."""
111-
ctx.document["paths"] = self._reduced_paths(ctx)
112-
return ctx
113-
114-
def paths(self, ctx: "Init.Context") -> "Init.Context":
115-
"""Clear the paths of the context."""
116-
ctx.paths = None
117-
return ctx
118-
119-
def initialized(self, ctx: "Init.Context") -> "Init.Context":
120-
"""Process the initialized context."""
121-
for name, parameter in list(ctx.initialized.components.parameters.items()):
122-
if parameter.schema_._model_type is None:
123-
del ctx.initialized.components.parameters[name]
124-
break
125-
126-
for name, schema in list(ctx.initialized.components.schemas.items()):
127-
if schema._model_type is None:
128-
del ctx.initialized.components.schemas[name]
129-
break
130-
131-
for name, response in list(ctx.initialized.components.responses.items()):
132-
for k, v in response.content.items():
133-
if v.schema_._model_type is None:
134-
del ctx.initialized.components.responses[name]
135-
break
136-
137-
for name, requestBody in list(ctx.initialized.components.requestBodies.items()):
138-
for k, v in requestBody.content.items():
139-
if v.schema_._model_type is None:
140-
del ctx.initialized.components.requestBodies[name]
141-
break
142-
return ctx
143-
144-
class Reduced(Culled, LazyLoaded):
145-
pass

docs/source/api.rst

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
.. include:: links.rst
2+
23
***
34
API
45
***
@@ -342,3 +343,28 @@ document.
342343
.. autoexception:: HeadersMissingError
343344
:members:
344345
:undoc-members:
346+
347+
Extra
348+
=====
349+
350+
Cull & Reduce
351+
-------------
352+
353+
Reduce & Cull are Plugins limiting the models built to the minimum required to match the requirements of the supplied Operations
354+
355+
Code below will eleminate all schemas not required to serve the operations identified by the pattern/string match and http methods associated.
356+
.. code:: python
357+
358+
api = OpenAPI.load_sync(
359+
"http://127.0.0.1/api.yaml",
360+
plugins=[
361+
Cull({
362+
re.compile(r"/this/.*"): None,
363+
"/and/this":["get"]
364+
})
365+
],
366+
)
367+
368+
.. currentmodule:: aiopenapi3.extra
369+
.. autoclass:: Reduce
370+
.. autoclass:: Cull

docs/source/extra.rst

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
.. include:: links.rst
2+
3+
*****
4+
Extra
5+
*****
6+
7+
8+
Large Description Documents
9+
===========================
10+
11+
To assist working with large description documents it is possible to limit the models build to the minimum required.
12+
This "minimum required" by the requirements of the Operations.
13+
14+
Currently there is two Plugins to assist such reduction - :class:`aiopenapi3.extra.Reduce` and :class:`aiopenapi3.extra.Cull`.
15+
Cull is faster, Reduce assists in debugging.
16+
17+
Large description documents which are autogenerated by converting other service description document formats -such as odata-
18+
may benefit from additional changes to the description document to eliminate conversion artifacts depending on the converter used.
19+
20+
As an example for additional steps based on the Microsoft MS Graph API refer to :aioai3:ref:`tests.extra_test.MSGraph`.

docs/source/index.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ While aiopenapi3 supports some of the more exotic features of the Swagger/OpenAP
4242
* :ref:`advanced:Forms`
4343
* :ref:`advanced:mutualTLS` authentication
4444
* :ref:`Request <advanced:Request Streaming>` and :ref:`Response <advanced:Response Streaming>` streaming to reduce memory usage
45+
* Culling :ref:`extra:Large Description Documents`
4546

4647
some aspects of the specifications are implemented loose
4748

docs/source/toc.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Table of contents
1212
use
1313
advanced
1414
plugin
15+
extra
1516
api
1617

1718
.. toctree::

tests/extra_test.py

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111

1212
from aiopenapi3 import OpenAPI
1313
from aiopenapi3.loader import FileSystemLoader
14-
from aiopenapi3.extra import Culled, LazyLoaded, Reduced
14+
from aiopenapi3.extra import Cull, Reduce
1515

1616

17-
class PetStoreReduced(LazyLoaded):
17+
class PetStoreReduced(Reduce):
1818
def __init__(self):
1919
super().__init__({"/user/{username}": None})
2020

@@ -81,15 +81,11 @@ def parsed(self, ctx):
8181
return ctx
8282

8383

84-
class MSGraphCulled(MSGraph, Culled):
84+
class MSGraphCulled(MSGraph, Cull):
8585
pass
8686

8787

88-
class MSGraphLazyLoaded(MSGraph, LazyLoaded):
89-
pass
90-
91-
92-
class MSGraphReduced(MSGraph, Reduced):
88+
class MSGraphReduced(MSGraph, Reduce):
9389
pass
9490

9591

@@ -116,7 +112,8 @@ def test_reduced_small():
116112
return
117113

118114

119-
def test_reduced(with_extra_reduced, httpx_mock):
115+
@pytest.mark.parametrize("compressor", [Reduce, Cull])
116+
def test_reduced(with_extra_reduced, httpx_mock, compressor):
120117
api = OpenAPI.load_file(
121118
"http://127.0.0.1/api.yaml",
122119
with_extra_reduced,
@@ -135,7 +132,7 @@ def test_reduced(with_extra_reduced, httpx_mock):
135132
"http://127.0.0.1/api.yaml",
136133
with_extra_reduced,
137134
session_factory=httpx.Client,
138-
plugins=[LazyLoaded({"/A/{Path}": None})],
135+
plugins=[compressor({"/A/{Path}": None})],
139136
loader=FileSystemLoader(Path("tests/fixtures")),
140137
)
141138

@@ -163,7 +160,7 @@ def test_reduced(with_extra_reduced, httpx_mock):
163160
"http://127.0.0.1/api.yaml",
164161
with_extra_reduced,
165162
session_factory=httpx.Client,
166-
plugins=[LazyLoaded({re.compile("/B"): None})],
163+
plugins=[compressor({re.compile("/B"): None})],
167164
loader=FileSystemLoader(Path("tests/fixtures")),
168165
)
169166
assert "/A/{Path}" not in api.paths.paths

0 commit comments

Comments
 (0)