From ba0530d6b14eb07aab88cb9ad9e7d28c6425e3d0 Mon Sep 17 00:00:00 2001 From: Georg K Date: Fri, 11 Nov 2022 10:02:27 +0300 Subject: [PATCH] feat: add support for operationId in docstring; feat: v1.120.6 --- aiohttp_pydantic/oas/docstring_parser.py | 15 ++++++++++++++- aiohttp_pydantic/oas/struct.py | 11 +++++++++++ aiohttp_pydantic/oas/view.py | 1 + tests/test_oas/test_view.py | 2 ++ 4 files changed, 28 insertions(+), 1 deletion(-) diff --git a/aiohttp_pydantic/oas/docstring_parser.py b/aiohttp_pydantic/oas/docstring_parser.py index eda47ef..1ac33a9 100644 --- a/aiohttp_pydantic/oas/docstring_parser.py +++ b/aiohttp_pydantic/oas/docstring_parser.py @@ -120,6 +120,19 @@ def tags(docstring: str) -> List[str]: return [] +def operation_id(docstring: str) -> str | None: + """ + Extract the "OperationId:" block of the docstring. + """ + iterator = LinesIterator(docstring) + for line in iterator: + if re.fullmatch("operation_?id\\s*:.*", line, re.IGNORECASE): + iterator.rewind() + return line.split(":")[1].strip(' ') + + return None + + def operation(docstring: str) -> str: """ Extract all docstring except the "Status Code:" block. @@ -127,7 +140,7 @@ def operation(docstring: str) -> str: lines = LinesIterator(docstring) ret = [] for line in lines: - if re.fullmatch("status\\s+codes?\\s*:|tags\\s*:.*", line, re.IGNORECASE): + if re.fullmatch("status\\s+codes?\\s*:|tags\\s*:.*|operation_?id\\s*:.*", line, re.IGNORECASE): lines.rewind() for _ in _i_extract_block(lines): pass diff --git a/aiohttp_pydantic/oas/struct.py b/aiohttp_pydantic/oas/struct.py index e03a62d..0f63ec4 100644 --- a/aiohttp_pydantic/oas/struct.py +++ b/aiohttp_pydantic/oas/struct.py @@ -207,6 +207,17 @@ class OperationObject: else: self._spec.pop("tags", None) + @property + def operation_id(self) -> str | None: + return self._spec.get("operationId", None) + + @operation_id.setter + def operation_id(self, operation_id: str | None) -> None: + if operation_id: + self._spec["operationId"] = operation_id + else: + self._spec.pop("operationId", None) + class PathItem: def __init__(self, spec: dict): diff --git a/aiohttp_pydantic/oas/view.py b/aiohttp_pydantic/oas/view.py index 858d7c2..7d0473f 100644 --- a/aiohttp_pydantic/oas/view.py +++ b/aiohttp_pydantic/oas/view.py @@ -87,6 +87,7 @@ def _add_http_method_to_oas( if description: oas_operation.description = docstring_parser.operation(description) oas_operation.tags = docstring_parser.tags(description) + oas_operation.operation_id = docstring_parser.operation_id(description) status_code_descriptions = docstring_parser.status_code(description) else: status_code_descriptions = {} diff --git a/tests/test_oas/test_view.py b/tests/test_oas/test_view.py index 0bcdbf0..5ad6ea5 100644 --- a/tests/test_oas/test_view.py +++ b/tests/test_oas/test_view.py @@ -47,6 +47,7 @@ class PetCollectionView(PydanticView): Tags: pet Status Codes: 200: Successful operation + OperationId: createPet """ return web.json_response() @@ -147,6 +148,7 @@ async def test_generated_oas_should_have_pets_paths(generated_oas): async def test_pets_route_should_have_get_method(generated_oas): assert generated_oas["paths"]["/pets"]["get"] == { "description": "Get a list of pets", + "operationId": "createPet", "tags": ["pet"], "parameters": [ {