From 4e548f1f3bc3dfcc2e83bfa23d0885f2d82b6f0b Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Tue, 1 Jun 2021 21:16:12 +0900 Subject: [PATCH 01/13] WIP --- fastapi_code_generator/parser.py | 51 ++++++++++++++------------------ 1 file changed, 23 insertions(+), 28 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 0af2321..05f2448 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -421,32 +421,6 @@ class Path(CachedPropertyModel): components: Dict[str, Any] = {} openapi_model_parser: OpenAPIModelParser - @root_validator(pre=True) - def validate_root(cls, values: Dict[str, Any]) -> Any: - path = values.get('path') - if path: - if isinstance(path, str): - operations = values.get('operations') - if operations: - if isinstance(operations, dict): - security = values.get('security', []) - components = values.get('components', {}) - openapi_model_parser = values.get('openapi_model_parser') - return { - 'path': path, - 'operations': dict( - **operations, - path=path, - security=security, - components=components, - openapi_model_parser=openapi_model_parser, - ), - 'security': security, - 'components': components, - 'openapi_model_parser': openapi_model_parser, - } - return values - @cached_property def exists_operations(self) -> List[Operation]: if self.operations: @@ -512,6 +486,27 @@ def parse_info( ) -> Optional[List[Dict[str, List[str]]]]: return openapi.get('info') + def parse_path( + self, + path: str, + operations: Dict[str, Any], + security: Optional[List[Dict[str, Any]]] = None, + components: Optional[Dict[str, Any]] = None, + ) -> Optional[Path]: + return Path( + path=path, + operations=Operations( + **operations, + path=path, + security=security, + components=components, + openapi_model_parser=self.openapi_model_parser, + ), + security=security, + components=components, + openapi_model_parser=self.openapi_model_parser, + ) + def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: security = self.parse_security(openapi) info = self.parse_info(openapi) @@ -519,13 +514,13 @@ def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: [ operation for path_name, operations in openapi['paths'].items() - for operation in Path( + for operation in self.parse_path( path=UsefulStr(path_name), operations=operations, security=security, components=openapi.get('components', {}), - openapi_model_parser=self.openapi_model_parser, ).exists_operations + if path_name and operations ], info, ) From a6ee6d22ef45f18cd1922fff1a57ef44c4de4600 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Wed, 2 Jun 2021 20:26:40 +0900 Subject: [PATCH 02/13] add parser methods --- fastapi_code_generator/parser.py | 114 +++++++++++++++++++------------ 1 file changed, 71 insertions(+), 43 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 05f2448..582a260 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -112,6 +112,14 @@ class Operation(CachedPropertyModel): tags: Optional[List[str]] openapi_model_parser: OpenAPIModelParser + def __init__(self, **values: Any) -> None: + super().__init__(**values) # type: ignore + # create imports + self.arguments + self.snake_case_arguments + self.request + self.response + @cached_property def root_path(self) -> UsefulStr: paths = self.path.split("/") @@ -376,41 +384,18 @@ class Config: components: Dict[str, Any] = {} openapi_model_parser: OpenAPIModelParser - @root_validator(pre=True) - def inject_path_and_type_to_operation(cls, values: Dict[str, Any]) -> Any: - path: Any = values.get('path') - openapi_model_parser: OpenAPIModelParser = values.get('openapi_model_parser') - return dict( - **{ - o: dict( - **values[o], - path=path, - type=o, - components=values.get('components', {}), - openapi_model_parser=openapi_model_parser, - ) - for o in OPERATION_NAMES - if o in values - }, - path=path, - parameters=values.get('parameters', []), - security=values.get('security'), - components=values.get('components', {}), - openapi_model_parser=openapi_model_parser, - ) - @root_validator def inject_parameters_and_security_to_operation(cls, values: Dict[str, Any]) -> Any: security = values.get('security') + parameters = values.get('parameters') for operation_name in OPERATION_NAMES: operation = values.get(operation_name) - if operation: - parameters = values.get('parameters') - if parameters: - operation.parameters.extend(parameters) - if security is not None and operation.security is None: - operation.security = security - + if not operation: + continue + if parameters: + operation.parameters.extend(parameters) + if security is not None and operation.security is None: + operation.security = security return values @@ -447,11 +432,6 @@ def __init__( self.imports: Imports = Imports() self.info = info for operation in self.operations: - # create imports - operation.arguments - operation.snake_case_arguments - operation.request - operation.response self.imports.append(operation.imports) @@ -486,21 +466,68 @@ def parse_info( ) -> Optional[List[Dict[str, List[str]]]]: return openapi.get('info') + def parse_operation( + self, + type_: str, + path: str, + operation: Dict[str, Any], + components: Dict[str, Any], + parameters: List[Any], + ) -> Operation: + if 'parameters' in operation: + operation['parameters'].extend(parameters) + else: + operation['parameters'] = parameters + return Operation( + **operation, + path=path, # type: ignore + type=type_, # type: ignore + components=components, + openapi_model_parser=self.openapi_model_parser, + ) + + def parse_operations( + self, + *, + path: str, + operations: Dict[str, Any], + components: Dict[str, Any], + security: Optional[List[Dict[str, List[str]]]] = None, + ) -> Operations: + parameters = operations.get('parameters', []) + return Operations( + **{ + o: self.parse_operation( + operation=operations[o], + path=path, + type_=o, + components=components, + parameters=parameters, + ) + for o in OPERATION_NAMES + if o in operations + }, + path=path, # type: ignore + parameters=parameters, + security=security, + components=components, + openapi_model_parser=self.openapi_model_parser, + ) + def parse_path( self, path: str, operations: Dict[str, Any], + components: Dict[str, Any], security: Optional[List[Dict[str, Any]]] = None, - components: Optional[Dict[str, Any]] = None, - ) -> Optional[Path]: + ) -> Path: return Path( - path=path, - operations=Operations( - **operations, + path=path, # type: ignore + operations=self.parse_operations( path=path, - security=security, + operations=operations, components=components, - openapi_model_parser=self.openapi_model_parser, + security=security, ), security=security, components=components, @@ -510,6 +537,7 @@ def parse_path( def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: security = self.parse_security(openapi) info = self.parse_info(openapi) + components = openapi.get('components', {}) return ParsedObject( [ operation @@ -518,7 +546,7 @@ def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: path=UsefulStr(path_name), operations=operations, security=security, - components=openapi.get('components', {}), + components=components, ).exists_operations if path_name and operations ], From 5522934fd82466e90c62b41f72771d7648d8aa25 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Thu, 3 Jun 2021 23:50:08 +0900 Subject: [PATCH 03/13] remove Operations --- fastapi_code_generator/parser.py | 133 +++++-------------------------- 1 file changed, 18 insertions(+), 115 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 582a260..9969045 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -366,60 +366,6 @@ def response(self) -> str: ] -class Operations(BaseModel): - class Config: - arbitrary_types_allowed = (OpenAPIModelParser,) - - parameters: List[Dict[str, Any]] = [] - get: Optional[Operation] = None - put: Optional[Operation] = None - post: Optional[Operation] = None - delete: Optional[Operation] = None - patch: Optional[Operation] = None - head: Optional[Operation] = None - options: Optional[Operation] = None - trace: Optional[Operation] = None - path: UsefulStr - security: Optional[List[Dict[str, List[str]]]] = [] - components: Dict[str, Any] = {} - openapi_model_parser: OpenAPIModelParser - - @root_validator - def inject_parameters_and_security_to_operation(cls, values: Dict[str, Any]) -> Any: - security = values.get('security') - parameters = values.get('parameters') - for operation_name in OPERATION_NAMES: - operation = values.get(operation_name) - if not operation: - continue - if parameters: - operation.parameters.extend(parameters) - if security is not None and operation.security is None: - operation.security = security - return values - - -class Path(CachedPropertyModel): - path: UsefulStr - operations: Optional[Operations] = None - security: Optional[List[Dict[str, List[str]]]] = [] - components: Dict[str, Any] = {} - openapi_model_parser: OpenAPIModelParser - - @cached_property - def exists_operations(self) -> List[Operation]: - if self.operations: - return [ - getattr(self.operations, operation_name) - for operation_name in OPERATION_NAMES - if getattr(self.operations, operation_name) - ] - return [] - - -Path.update_forward_refs() - - class ParsedObject: def __init__( self, @@ -473,11 +419,14 @@ def parse_operation( operation: Dict[str, Any], components: Dict[str, Any], parameters: List[Any], + security: Optional[List[Dict[str, List[str]]]] = None, ) -> Operation: if 'parameters' in operation: operation['parameters'].extend(parameters) else: operation['parameters'] = parameters + if security is not None and 'security' not in operation: + operation['security'] = security return Operation( **operation, path=path, # type: ignore @@ -486,69 +435,23 @@ def parse_operation( openapi_model_parser=self.openapi_model_parser, ) - def parse_operations( - self, - *, - path: str, - operations: Dict[str, Any], - components: Dict[str, Any], - security: Optional[List[Dict[str, List[str]]]] = None, - ) -> Operations: - parameters = operations.get('parameters', []) - return Operations( - **{ - o: self.parse_operation( - operation=operations[o], - path=path, - type_=o, - components=components, - parameters=parameters, - ) - for o in OPERATION_NAMES - if o in operations - }, - path=path, # type: ignore - parameters=parameters, - security=security, - components=components, - openapi_model_parser=self.openapi_model_parser, - ) - - def parse_path( - self, - path: str, - operations: Dict[str, Any], - components: Dict[str, Any], - security: Optional[List[Dict[str, Any]]] = None, - ) -> Path: - return Path( - path=path, # type: ignore - operations=self.parse_operations( - path=path, - operations=operations, - components=components, - security=security, - ), - security=security, - components=components, - openapi_model_parser=self.openapi_model_parser, - ) - def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: security = self.parse_security(openapi) info = self.parse_info(openapi) components = openapi.get('components', {}) - return ParsedObject( - [ - operation - for path_name, operations in openapi['paths'].items() - for operation in self.parse_path( - path=UsefulStr(path_name), - operations=operations, - security=security, + results = [] + for path_name, operations in openapi['paths'].items(): + parameters = operations.get('parameters', []) + for operation in operations: + if operation not in OPERATION_NAMES: + continue + parsed_operation = self.parse_operation( + operation=operations[operation], + path=path_name, + type_=operation, components=components, - ).exists_operations - if path_name and operations - ], - info, - ) + parameters=parameters, + security=security, + ) + results.append(parsed_operation) + return ParsedObject(results, info,) From 546f97b71ec4dc95ede08b95f93f0f0e6709c411 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Fri, 4 Jun 2021 00:05:51 +0900 Subject: [PATCH 04/13] change type to method --- fastapi_code_generator/parser.py | 39 ++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 9969045..ab4d1a0 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -99,7 +99,7 @@ def argument(self) -> str: class Operation(CachedPropertyModel): - type: UsefulStr + method: UsefulStr path: UsefulStr operationId: Optional[UsefulStr] summary: Optional[str] @@ -120,6 +120,13 @@ def __init__(self, **values: Any) -> None: self.request self.response + @cached_property + def type(self) -> UsefulStr: + """ + backwards compatibility + """ + return self.method + @cached_property def root_path(self) -> UsefulStr: paths = self.path.split("/") @@ -414,7 +421,7 @@ def parse_info( def parse_operation( self, - type_: str, + method: str, path: str, operation: Dict[str, Any], components: Dict[str, Any], @@ -430,7 +437,7 @@ def parse_operation( return Operation( **operation, path=path, # type: ignore - type=type_, # type: ignore + method=method, # type: ignore components=components, openapi_model_parser=self.openapi_model_parser, ) @@ -439,19 +446,21 @@ def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: security = self.parse_security(openapi) info = self.parse_info(openapi) components = openapi.get('components', {}) - results = [] - for path_name, operations in openapi['paths'].items(): - parameters = operations.get('parameters', []) - for operation in operations: - if operation not in OPERATION_NAMES: - continue - parsed_operation = self.parse_operation( - operation=operations[operation], + return ParsedObject( + [ + self.parse_operation( + operation=raw_operation, path=path_name, - type_=operation, + method=method, components=components, - parameters=parameters, + parameters=raw_operations.get('parameters', []), security=security, ) - results.append(parsed_operation) - return ParsedObject(results, info,) + for path_name, raw_operations in openapi[ + 'paths' + ].items() # type: str, Dict[str, Any] + for method, raw_operation in raw_operations.items() + if method in OPERATION_NAMES + ], + info, + ) From 1d872dade1b2c42ac0c800ca502685903318127c Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Fri, 4 Jun 2021 00:12:24 +0900 Subject: [PATCH 05/13] improve parameters --- fastapi_code_generator/parser.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index ab4d1a0..999ebb7 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -421,17 +421,19 @@ def parse_info( def parse_operation( self, + *, method: str, path: str, operation: Dict[str, Any], components: Dict[str, Any], - parameters: List[Any], - security: Optional[List[Dict[str, List[str]]]] = None, + parameters: Optional[List[Any]], + security: Optional[List[Dict[str, List[str]]]], ) -> Operation: - if 'parameters' in operation: - operation['parameters'].extend(parameters) - else: - operation['parameters'] = parameters + if parameters: + if 'parameters' in operation: + operation['parameters'].extend(parameters) + else: + operation['parameters'] = parameters if security is not None and 'security' not in operation: operation['security'] = security return Operation( @@ -453,12 +455,10 @@ def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: path=path_name, method=method, components=components, - parameters=raw_operations.get('parameters', []), + parameters=raw_operations.get('parameters'), security=security, ) - for path_name, raw_operations in openapi[ - 'paths' - ].items() # type: str, Dict[str, Any] + for path_name, raw_operations in openapi['paths'].items() for method, raw_operation in raw_operations.items() if method in OPERATION_NAMES ], From 6fa07e1a940a9eb0858c9c4dab609a0fbd9987ce Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sun, 18 Jul 2021 00:45:23 +0900 Subject: [PATCH 06/13] Refactoring parser --- fastapi_code_generator/__main__.py | 41 +- fastapi_code_generator/parser.py | 528 +++++++-------- poetry.lock | 602 ++++++++++-------- pyproject.toml | 2 +- .../body_and_parameters/models.py | 32 +- 5 files changed, 651 insertions(+), 554 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 1485a31..71f6c15 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -5,7 +5,10 @@ import typer from datamodel_code_generator import PythonVersion, chdir from datamodel_code_generator.format import CodeFormatter +from datamodel_code_generator.imports import Import from datamodel_code_generator.parser.openapi import OpenAPIParser as OpenAPIModelParser +from datamodel_code_generator.reference import Reference +from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader from fastapi_code_generator.parser import MODEL_PATH, OpenAPIParser, ParsedObject @@ -26,6 +29,16 @@ def main( return generate_code(input_name, input_text, output_dir, template_dir) +def _get_most_of_reference(data_type: DataType) -> Optional[Reference]: + if data_type.reference: + return data_type.reference + for data_type in data_type.data_types: + reference = _get_most_of_reference(data_type) + if reference: + return reference + return None + + def generate_code( input_name: str, input_text: str, output_dir: Path, template_dir: Optional[Path] ) -> None: @@ -34,10 +47,12 @@ def generate_code( if not template_dir: template_dir = BUILTIN_TEMPLATE_DIR - model_parser = OpenAPIModelParser(source=input_text,) + # model_parser = OpenAPIModelParser(source=input_text,) - parser = OpenAPIParser(input_name, input_text, openapi_model_parser=model_parser) - parsed_object: ParsedObject = parser.parse() + parser = OpenAPIParser(input_text) + # parsed_object: ParsedObject = parser.parse() + models = parser.parse() + parsed_object = parser.parse_paths() environment: Environment = Environment( loader=FileSystemLoader( @@ -45,6 +60,16 @@ def generate_code( encoding="utf8", ), ) + parsed_object.imports.update(parser.imports) + for data_type in parser.data_types: + reference = _get_most_of_reference(data_type) + if reference: + parsed_object.imports.append(data_type.all_imports) + parsed_object.imports.append( + Import.from_full_path(f'.models.{reference.name}') + ) + for from_, imports in parser.imports_for_fastapi.items(): + parsed_object.imports[from_].update(imports) results: Dict[Path, str] = {} code_formatter = CodeFormatter(PythonVersion.PY_38, Path().resolve()) for target in template_dir.rglob("*"): @@ -68,13 +93,13 @@ def generate_code( print("", file=file) print(code.rstrip(), file=file) - with chdir(output_dir): - results = model_parser.parse() - if not results: + # with chdir(output_dir): + # results = parser.parse() + if not models: return - elif isinstance(results, str): + elif isinstance(models, str): output = output_dir / MODEL_PATH - modules = {output: (results, input_name)} + modules = {output: (models, input_name)} else: raise Exception('Modular references are not supported in this version') diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 999ebb7..0971708 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -3,19 +3,50 @@ import pathlib import re from contextvars import ContextVar -from typing import Any, Dict, List, Optional, Pattern, Union +from typing import ( + Any, + Callable, + DefaultDict, + Dict, + Iterable, + List, + Mapping, + Optional, + Pattern, + Sequence, + Set, + Type, + Union, +) +from urllib.parse import ParseResult import stringcase -from datamodel_code_generator import cached_property, load_yaml, snooper_to_methods +from datamodel_code_generator import ( + DefaultPutDict, + LiteralType, + OpenAPIScope, + PythonVersion, + cached_property, + snooper_to_methods, +) from datamodel_code_generator.imports import Import, Imports +from datamodel_code_generator.model import DataModel, DataModelFieldBase +from datamodel_code_generator.model import pydantic as pydantic_model from datamodel_code_generator.model.pydantic import DataModelField from datamodel_code_generator.parser.jsonschema import ( JsonSchemaObject, get_model_by_path, ) +from datamodel_code_generator.parser.openapi import MediaObject from datamodel_code_generator.parser.openapi import OpenAPIParser as OpenAPIModelParser -from datamodel_code_generator.types import DataType -from pydantic import BaseModel, root_validator +from datamodel_code_generator.parser.openapi import ( + ParameterObject, + ReferenceObject, + RequestBodyObject, + ResponseObject, +) +from datamodel_code_generator.types import DataType, DataTypeManager, StrictTypes +from pydantic import BaseModel MODEL_PATH: pathlib.Path = pathlib.Path("models.py") @@ -105,20 +136,15 @@ class Operation(CachedPropertyModel): summary: Optional[str] parameters: List[Dict[str, Any]] = [] responses: Dict[UsefulStr, Any] = {} - requestBody: Dict[str, Any] = {} + # requestBody: Dict[str, Any] = {} imports: List[Import] = [] security: Optional[List[Dict[str, List[str]]]] = None - components: Dict[str, Any] = {} + # components: Dict[str, Any] = {} tags: Optional[List[str]] - openapi_model_parser: OpenAPIModelParser - - def __init__(self, **values: Any) -> None: - super().__init__(**values) # type: ignore - # create imports - self.arguments - self.snake_case_arguments - self.request - self.response + arguments: str = '' + snake_case_arguments: str = '' + request: Optional[Argument] = None + response: str = '' @cached_property def type(self) -> UsefulStr: @@ -138,88 +164,6 @@ def snake_case_path(self) -> str: r"{([^\}]+)}", lambda m: stringcase.snakecase(m.group()), self.path ) - @cached_property - def request(self) -> Optional[Argument]: - arguments: List[Argument] = [] - for requests in self.request_objects: - for content_type, schema in requests.contents.items(): - # TODO: support other content-types - if RE_APPLICATION_JSON_PATTERN.match(content_type): - data_type = self.get_data_type(schema, 'request') - arguments.append( - # TODO: support multiple body - Argument( - name='body', # type: ignore - type_hint=data_type.type_hint, - required=requests.required, - ) - ) - self.imports.extend(data_type.imports) - elif content_type == 'application/x-www-form-urlencoded': - arguments.append( - # TODO: support form with `Form()` - Argument( - name='request', # type: ignore - type_hint='Request', # type: ignore - required=True, - ) - ) - self.imports.append( - Import.from_full_path('starlette.requests.Request') - ) - if not arguments: - return None - return arguments[0] - - @cached_property - def request_objects(self) -> List[Request]: - requests: List[Request] = [] - contents: Dict[str, JsonSchemaObject] = {} - ref: Optional[str] = self.requestBody.get('$ref') - if ref: - request_body = get_ref_body(ref, self.openapi_model_parser, self.components) - else: - request_body = self.requestBody - for content_type, obj in request_body.get('content', {}).items(): - contents[content_type] = ( - JsonSchemaObject.parse_obj(obj['schema']) if 'schema' in obj else None - ) - requests.append( - Request( - description=request_body.get("description"), - contents=contents, - required=request_body.get("required") is True, - ) - ) - return requests - - @cached_property - def response_objects(self) -> List[Response]: - responses: List[Response] = [] - for status_code, detail in self.responses.items(): - ref: Optional[str] = detail.get('$ref') - if ref: - ref_body = get_ref_body(ref, self.openapi_model_parser, self.components) - content = ref_body.get("content", {}) - description = ref_body.get("description") - else: - content = detail.get("content", {}) - description = detail.get("description") - contents = {} - for content_type, obj in content.items(): - contents[content_type] = ( - JsonSchemaObject.parse_obj(obj["schema"]) - if "schema" in obj - else None - ) - - responses.append( - Response( - status_code=status_code, description=description, contents=contents, - ) - ) - return responses - @cached_property def function_name(self) -> str: if self.operationId: @@ -229,72 +173,140 @@ def function_name(self) -> str: name = f"{self.type}{path}" return stringcase.snakecase(name) - @cached_property - def arguments(self) -> str: - return self.get_arguments(snake_case=False) - @cached_property - def snake_case_arguments(self) -> str: - return self.get_arguments(snake_case=True) +OPERATION_NAMES: List[str] = [ + "get", + "put", + "post", + "delete", + "patch", + "head", + "options", + "trace", +] - def get_arguments(self, snake_case: bool) -> str: - return ", ".join( - argument.argument for argument in self.get_argument_list(snake_case) + +class ParsedObject: + def __init__( + self, + parsed_operations: List[Operation], + info: Optional[List[Dict[str, Any]]] = None, + ): + self.operations: List[Operation] = sorted( + parsed_operations, key=lambda m: m.path ) + self.imports: Imports = Imports() + self.info = info + for operation in self.operations: + self.imports.append(operation.imports) - @cached_property - def argument_list(self) -> List[Argument]: - return self.get_argument_list(False) - def get_argument_list(self, snake_case: bool) -> List[Argument]: - arguments: List[Argument] = [] +@snooper_to_methods(max_variable_length=None) +class OpenAPIParser(OpenAPIModelParser): + def __init__( + self, + source: Union[str, pathlib.Path, List[pathlib.Path], ParseResult], + *, + data_model_type: Type[DataModel] = pydantic_model.BaseModel, + data_model_root_type: Type[DataModel] = pydantic_model.CustomRootType, + data_type_manager_type: Type[DataTypeManager] = pydantic_model.DataTypeManager, + data_model_field_type: Type[DataModelFieldBase] = pydantic_model.DataModelField, + base_class: Optional[str] = None, + custom_template_dir: Optional[pathlib.Path] = None, + extra_template_data: Optional[DefaultDict[str, Dict[str, Any]]] = None, + target_python_version: PythonVersion = PythonVersion.PY_37, + dump_resolve_reference_action: Optional[Callable[[Iterable[str]], str]] = None, + validation: bool = False, + field_constraints: bool = False, + snake_case_field: bool = False, + strip_default_none: bool = False, + aliases: Optional[Mapping[str, str]] = None, + allow_population_by_field_name: bool = False, + apply_default_values_for_required_fields: bool = False, + force_optional_for_required_fields: bool = False, + class_name: Optional[str] = None, + use_standard_collections: bool = False, + base_path: Optional[pathlib.Path] = None, + use_schema_description: bool = False, + reuse_model: bool = False, + encoding: str = 'utf-8', + enum_field_as_literal: Optional[LiteralType] = None, + set_default_enum_member: bool = False, + strict_nullable: bool = False, + use_generic_container_types: bool = False, + enable_faux_immutability: bool = False, + remote_text_cache: Optional[DefaultPutDict[str, str]] = None, + disable_appending_item_suffix: bool = False, + strict_types: Optional[Sequence[StrictTypes]] = None, + empty_enum_field_name: Optional[str] = None, + custom_class_name_generator: Optional[Callable[[str], str]] = None, + field_extra_keys: Optional[Set[str]] = None, + field_include_all_keys: bool = False, + model_module_name: Optional[str] = None, + ): + super().__init__( + source=source, + data_model_type=data_model_type, + data_model_root_type=data_model_root_type, + data_type_manager_type=data_type_manager_type, + data_model_field_type=data_model_field_type, + base_class=base_class, + custom_template_dir=custom_template_dir, + extra_template_data=extra_template_data, + target_python_version=target_python_version, + dump_resolve_reference_action=dump_resolve_reference_action, + validation=validation, + field_constraints=field_constraints, + snake_case_field=snake_case_field, + strip_default_none=strip_default_none, + aliases=aliases, + allow_population_by_field_name=allow_population_by_field_name, + apply_default_values_for_required_fields=apply_default_values_for_required_fields, + force_optional_for_required_fields=force_optional_for_required_fields, + class_name=class_name, + use_standard_collections=use_standard_collections, + base_path=base_path, + use_schema_description=use_schema_description, + reuse_model=reuse_model, + encoding=encoding, + enum_field_as_literal=enum_field_as_literal, + set_default_enum_member=set_default_enum_member, + strict_nullable=strict_nullable, + use_generic_container_types=use_generic_container_types, + enable_faux_immutability=enable_faux_immutability, + remote_text_cache=remote_text_cache, + disable_appending_item_suffix=disable_appending_item_suffix, + strict_types=strict_types, + empty_enum_field_name=empty_enum_field_name, + custom_class_name_generator=custom_class_name_generator, + field_extra_keys=field_extra_keys, + field_include_all_keys=field_include_all_keys, + openapi_scopes=[OpenAPIScope.Schemas, OpenAPIScope.Paths], + ) + if model_module_name: + model_module_name_var.set(model_module_name) + self.operations: Dict[str, Operation] = {} + self._temporary_operation_items: Dict[str, Any] = {} + self.imports_for_fastapi: Imports = Imports() + self.data_types: List[DataType] = [] - if self.parameters: - for parameter in self.parameters: - arguments.append(self.get_parameter_type(parameter, snake_case)) + def parse_info( + self, openapi: Dict[str, Any] + ) -> Optional[List[Dict[str, List[str]]]]: + return openapi.get('info') - if self.request: - arguments.append(self.request) - return arguments - - def get_data_type(self, schema: JsonSchemaObject, suffix: str = '') -> DataType: - if schema.ref: - data_type = self.openapi_model_parser.get_ref_data_type(schema.ref) - self.imports.append( - Import( - # TODO: Improve import statements - from_=model_module_name_var.get(), - import_=data_type.type_hint, - ) - ) - return data_type - elif schema.is_array: - # TODO: Improve handling array - items = schema.items if isinstance(schema.items, list) else [schema.items] - return self.openapi_model_parser.data_type( - data_types=[self.get_data_type(i, suffix) for i in items], is_list=True - ) - elif schema.is_object: - camelcase_path = stringcase.camelcase(self.path[1:].replace("/", "_")) - capitalized_suffix = suffix.capitalize() - name: str = f'{camelcase_path}{self.type.capitalize()}{capitalized_suffix}' - path = ['paths', self.path, self.type, capitalized_suffix] - - data_type = self.openapi_model_parser.parse_object(name, schema, path) - - self.imports.append( - Import(from_=model_module_name_var.get(), import_=data_type.type_hint,) - ) - return data_type - - return self.openapi_model_parser.get_data_type(schema) + def parse_parameters(self, parameters: ParameterObject, path: List[str]) -> None: + super().parse_parameters(parameters, path) def get_parameter_type( - self, parameter: Dict[str, Union[str, Dict[str, Any]]], snake_case: bool + self, + parameter: Dict[str, Union[str, Dict[str, Any]]], + snake_case: bool, + path: List[str], ) -> Argument: ref: Optional[str] = parameter.get('$ref') # type: ignore if ref: - parameter = get_ref_body(ref, self.openapi_model_parser, self.components) + parameter = self.get_ref_model(ref) name: str = parameter["name"] # type: ignore orig_name = name if snake_case: @@ -314,15 +326,17 @@ def get_parameter_type( field = DataModelField( name=name, - data_type=self.get_data_type(schema, 'parameter'), + data_type=self.parse_schema(name, schema, [*path, name]), required=parameter.get("required") or parameter.get("in") == "path", ) - self.imports.extend(field.imports) + if orig_name != name: has_in = parameter.get('in') if has_in and isinstance(has_in, str): param_is = has_in.lower().capitalize() - self.imports.append(Import(from_='fastapi', import_=param_is)) + self.imports_for_fastapi.append( + Import(from_='fastapi', import_=param_is) + ) default: Optional[ str ] = f"{param_is}({'...' if field.required else repr(schema.default)}, alias='{orig_name}')" @@ -334,6 +348,8 @@ def get_parameter_type( ) else: default = repr(schema.default) if schema.has_default else None + self.imports_for_fastapi.append(field.imports) + self.data_types.append(field.data_type) return Argument( name=field.name, type_hint=field.type_hint, @@ -342,125 +358,113 @@ def get_parameter_type( required=field.required, ) - @cached_property - def response(self) -> str: - data_types: List[DataType] = [] - for response in self.response_objects: - # expect 2xx - if response.status_code.startswith("2"): - for content_type, schema in response.contents.items(): - if RE_APPLICATION_JSON_PATTERN.match(content_type): - data_type = self.get_data_type(schema, 'response') - data_types.append(data_type) - self.imports.extend(data_type.imports) - - if not data_types: - return "None" - if len(data_types) > 1: - return self.openapi_model_parser.data_type(data_types=data_types).type_hint - return data_types[0].type_hint + def get_arguments(self, snake_case: bool, path: List[str]) -> str: + return ", ".join( + argument.argument for argument in self.get_argument_list(snake_case, path) + ) + def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument]: + arguments: List[Argument] = [] -OPERATION_NAMES: List[str] = [ - "get", - "put", - "post", - "delete", - "patch", - "head", - "options", - "trace", -] + parameters = self._temporary_operation_items.get('_parameters') + if parameters: + for parameter in parameters: + arguments.append( + self.get_parameter_type( + parameter, snake_case, [*path, 'parameters'] + ) + ) + request = self._temporary_operation_items.get('_request') + if request: + arguments.append(request) + return arguments -class ParsedObject: - def __init__( - self, - parsed_operations: List[Operation], - info: Optional[List[Dict[str, Any]]] = None, - ): - self.operations: List[Operation] = sorted( - parsed_operations, key=lambda m: m.path + def parse_request_body( + self, name: str, request_body: RequestBodyObject, path: List[str], + ) -> None: + super().parse_request_body(name, request_body, path) + arguments: List[Argument] = [] + for ( + media_type, + media_obj, + ) in request_body.content.items(): # type: str, MediaObject + if isinstance( + media_obj.schema_, (JsonSchemaObject, ReferenceObject) + ): # pragma: no cover + # TODO: support other content-types + if RE_APPLICATION_JSON_PATTERN.match(media_type): + if isinstance(media_obj.schema_, ReferenceObject): + data_type = self.get_ref_data_type(media_obj.schema_.ref) + else: + data_type = self.parse_schema( + name, media_obj.schema_, [*path, media_type] + ) + arguments.append( + # TODO: support multiple body + Argument( + name='body', # type: ignore + type_hint=data_type.type_hint, + required=request_body.required, + ) + ) + self.data_types.append(data_type) + elif media_type == 'application/x-www-form-urlencoded': + arguments.append( + # TODO: support form with `Form()` + Argument( + name='request', # type: ignore + type_hint='Request', # type: ignore + required=True, + ) + ) + self.imports_for_fastapi.append( + Import.from_full_path('starlette.requests.Request') + ) + self._temporary_operation_items['_request'] = ( + arguments[0] if arguments else None ) - self.imports: Imports = Imports() - self.info = info - for operation in self.operations: - self.imports.append(operation.imports) - -@snooper_to_methods(max_variable_length=None) -class OpenAPIParser: - def __init__( + def parse_responses( self, - input_name: str, - input_text: str, - openapi_model_parser: Optional[OpenAPIModelParser] = None, - model_module_name: Optional[str] = None, - ) -> None: - self.input_name: str = input_name - self.input_text: str = input_text - self.openapi_model_parser: OpenAPIModelParser = openapi_model_parser or OpenAPIModelParser( - source='' - ) - if model_module_name: - model_module_name_var.set(model_module_name) + name: str, + responses: Dict[str, Union[ResponseObject, ReferenceObject]], + path: List[str], + ) -> Dict[str, Dict[str, DataType]]: + data_types = super().parse_responses(name, responses, path) + status_code_200 = data_types.get('200') + if status_code_200: + data_type = list(status_code_200.values())[0] + if data_type: + self.data_types.append(data_type) + type_hint = data_type.type_hint # TODO: change to lazy loading + else: + type_hint = 'None' + self._temporary_operation_items['response'] = type_hint - def parse(self) -> ParsedObject: - openapi = load_yaml(self.input_text) - return self.parse_paths(openapi) + return data_types - def parse_security( - self, openapi: Dict[str, Any] - ) -> Optional[List[Dict[str, List[str]]]]: - return openapi.get('security') + def parse_operation(self, raw_operation: Dict[str, Any], path: List[str],) -> None: + self._temporary_operation_items = {} + super().parse_operation(raw_operation, path) + resolved_path = self.model_resolver.resolve_ref(path) + path_name, method = path[-2:] - def parse_info( - self, openapi: Dict[str, Any] - ) -> Optional[List[Dict[str, List[str]]]]: - return openapi.get('info') + self._temporary_operation_items['_parameters'] = raw_operation.get('parameters') + self._temporary_operation_items['arguments'] = self.get_arguments( + snake_case=False, path=path + ) + self._temporary_operation_items['snake_case_arguments'] = self.get_arguments( + snake_case=True, path=path + ) - def parse_operation( - self, - *, - method: str, - path: str, - operation: Dict[str, Any], - components: Dict[str, Any], - parameters: Optional[List[Any]], - security: Optional[List[Dict[str, List[str]]]], - ) -> Operation: - if parameters: - if 'parameters' in operation: - operation['parameters'].extend(parameters) - else: - operation['parameters'] = parameters - if security is not None and 'security' not in operation: - operation['security'] = security - return Operation( - **operation, - path=path, # type: ignore + self.operations[resolved_path] = Operation( + **raw_operation, + **self._temporary_operation_items, + path=f'/{path_name}', # type: ignore method=method, # type: ignore - components=components, - openapi_model_parser=self.openapi_model_parser, ) - def parse_paths(self, openapi: Dict[str, Any]) -> ParsedObject: - security = self.parse_security(openapi) - info = self.parse_info(openapi) - components = openapi.get('components', {}) - return ParsedObject( - [ - self.parse_operation( - operation=raw_operation, - path=path_name, - method=method, - components=components, - parameters=raw_operations.get('parameters'), - security=security, - ) - for path_name, raw_operations in openapi['paths'].items() - for method, raw_operation in raw_operations.items() - if method in OPERATION_NAMES - ], - info, - ) + def parse_paths(self) -> ParsedObject: + info = self.parse_info(self.raw_obj) + return ParsedObject(list(self.operations.values()), info,) diff --git a/poetry.lock b/poetry.lock index 8ad096e..eede2e1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,3 +1,21 @@ +[[package]] +name = "anyio" +version = "3.2.1" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" +typing-extensions = {version = "*", markers = "python_version < \"3.8\""} + +[package.extras] +doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16)"] + [[package]] name = "appdirs" version = "1.4.4" @@ -8,14 +26,14 @@ python-versions = "*" [[package]] name = "argcomplete" -version = "1.12.2" +version = "1.12.3" description = "Bash tab completion for argparse" category = "main" optional = false python-versions = "*" [package.dependencies] -importlib-metadata = {version = ">=0.23,<4", markers = "python_version == \"3.7\""} +importlib-metadata = {version = ">=0.23,<5", markers = "python_version == \"3.7\""} [package.extras] test = ["coverage", "flake8", "pexpect", "wheel"] @@ -30,17 +48,17 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "attrs" -version = "20.3.0" +version = "21.2.0" description = "Classes Without Boilerplate" category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.extras] -dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface", "furo", "sphinx", "pre-commit"] -docs = ["furo", "sphinx", "zope.interface"] -tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "zope.interface"] -tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six"] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] [[package]] name = "black" @@ -64,7 +82,7 @@ d = ["aiohttp (>=3.3.2)", "aiohttp-cors"] [[package]] name = "certifi" -version = "2020.12.5" +version = "2021.5.30" description = "Python package for providing Mozilla's CA Bundle." category = "main" optional = false @@ -102,19 +120,17 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" -[package.dependencies] -toml = {version = "*", optional = true, markers = "extra == \"toml\""} - [package.extras] toml = ["toml"] [[package]] name = "datamodel-code-generator" -version = "0.11.6" +version = "0.11.9.dev7+g902958d" description = "Datamodel Code Generator" category = "main" optional = false python-versions = ">=3.6.1" +develop = false [package.dependencies] argcomplete = ">=1.10,<2.0" @@ -134,14 +150,20 @@ PySnooper = ">=0.4.1,<1.0.0" toml = ">=0.10.0,<1.0.0" [package.extras] -all = ["pytest-runner", "setuptools-scm", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "httpx", "mkdocs", "mkdocs-material", "wheel", "twine", "codecov"] +all = ["pytest-runner", "setuptools-scm", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml", "httpx", "mkdocs", "mkdocs-material", "wheel", "twine", "codecov"] ci = ["codecov"] docs = ["mkdocs", "mkdocs-material"] http = ["httpx"] setup = ["pytest-runner", "setuptools-scm"] -test = ["pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun"] +test = ["pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml"] wheel = ["wheel", "twine"] +[package.source] +type = "git" +url = "https://github.com/koxudaxi/datamodel-code-generator.git" +reference = "improve_openapi_parser" +resolved_reference = "902958d1acbe3433406db228f11ed919203dc4a3" + [[package]] name = "dnspython" version = "2.1.0" @@ -159,11 +181,11 @@ trio = ["trio (>=0.14.0)", "sniffio (>=1.1)"] [[package]] name = "email-validator" -version = "1.1.2" +version = "1.1.3" description = "A robust email syntax and deliverability validation library for Python 2.x/3.x." category = "main" optional = false -python-versions = "*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" [package.dependencies] dnspython = ">=1.15.0" @@ -198,14 +220,15 @@ python-versions = ">=3.6" [[package]] name = "httpcore" -version = "0.12.3" +version = "0.13.6" description = "A minimal low-level HTTP client." category = "main" optional = false python-versions = ">=3.6" [package.dependencies] -h11 = "<1.0.0" +anyio = ">=3.0.0,<4.0.0" +h11 = ">=0.11,<0.13" sniffio = ">=1.0.0,<2.0.0" [package.extras] @@ -213,7 +236,7 @@ http2 = ["h2 (>=3,<5)"] [[package]] name = "httpx" -version = "0.16.1" +version = "0.18.2" description = "The next generation HTTP client." category = "main" optional = false @@ -221,12 +244,12 @@ python-versions = ">=3.6" [package.dependencies] certifi = "*" -httpcore = ">=0.12.0,<0.13.0" +httpcore = ">=0.13.3,<0.14.0" rfc3986 = {version = ">=1.3,<2", extras = ["idna2008"]} sniffio = "*" [package.extras] -brotli = ["brotlipy (>=0.7.0,<0.8.0)"] +brotli = ["brotlicffi (>=1.0.0,<2.0.0)"] http2 = ["h2 (>=3.0.0,<4.0.0)"] [[package]] @@ -239,7 +262,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "importlib-metadata" -version = "3.4.0" +version = "4.6.1" description = "Read metadata from Python packages" category = "main" optional = false @@ -251,22 +274,20 @@ zipp = ">=0.5" [package.extras] docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] +perf = ["ipython"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "packaging", "pep517", "pyfakefs", "flufl.flake8", "pytest-perf (>=0.9.2)", "pytest-black (>=0.3.7)", "pytest-mypy", "importlib-resources (>=1.3)"] [[package]] name = "inflect" -version = "4.1.1" +version = "5.3.0" description = "Correctly generate plurals, singular nouns, ordinals, indefinite articles; convert numbers to words" category = "main" optional = false python-versions = ">=3.6" -[package.dependencies] -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} - [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "pygments", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "pytest-enabler", "pygments", "pytest-black (>=0.3.7)", "pytest-mypy"] [[package]] name = "iniconfig" @@ -276,6 +297,17 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "isodate" +version = "0.6.0" +description = "An ISO 8601 date/time/duration parser and formatter" +category = "main" +optional = false +python-versions = "*" + +[package.dependencies] +six = "*" + [[package]] name = "isort" version = "4.3.21" @@ -324,15 +356,15 @@ format_nongpl = ["idna", "jsonpointer (>1.13)", "webcolors", "rfc3986-validator [[package]] name = "markupsafe" -version = "1.1.1" +version = "2.0.1" description = "Safely add untrusted strings to HTML/XML markup." category = "main" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*" +python-versions = ">=3.6" [[package]] name = "mypy" -version = "0.812" +version = "0.910" description = "Optional static typing for Python" category = "dev" optional = false @@ -340,11 +372,13 @@ python-versions = ">=3.5" [package.dependencies] mypy-extensions = ">=0.4.3,<0.5.0" -typed-ast = ">=1.4.0,<1.5.0" +toml = "*" +typed-ast = {version = ">=1.4.0,<1.5.0", markers = "python_version < \"3.8\""} typing-extensions = ">=3.7.4" [package.extras] dmypy = ["psutil (>=4.0)"] +python2 = ["typed-ast (>=1.4.0,<1.5.0)"] [[package]] name = "mypy-extensions" @@ -354,29 +388,49 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "openapi-schema-validator" +version = "0.1.5" +description = "OpenAPI schema validation for Python" +category = "main" +optional = false +python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*, != 3.4.*" + +[package.dependencies] +isodate = "*" +jsonschema = ">=3.0.0" +six = "*" + +[package.extras] +isodate = ["isodate"] +rfc3339_validator = ["rfc3339-validator"] +strict_rfc3339 = ["strict-rfc3339"] + [[package]] name = "openapi-spec-validator" -version = "0.2.9" -description = "OpenAPI 2.0 (aka Swagger) and OpenAPI 3.0.0 spec validator" +version = "0.3.1" +description = "OpenAPI 2.0 (aka Swagger) and OpenAPI 3.0 spec validator" category = "main" optional = false -python-versions = "*" +python-versions = ">= 2.7, != 3.0.*, != 3.1.*, != 3.2.*, != 3.3.*, != 3.4.*" [package.dependencies] jsonschema = "*" +openapi-schema-validator = "*" PyYAML = ">=5.1" six = "*" [package.extras] dev = ["pre-commit"] +requests = ["requests"] [[package]] name = "packaging" -version = "20.9" +version = "21.0" description = "Core utilities for Python packages" category = "dev" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2" @@ -405,14 +459,14 @@ dev = ["pre-commit", "tox"] [[package]] name = "prance" -version = "0.20.2" +version = "0.21.2" description = "Resolving Swagger/OpenAPI 2.0 and 3.0.0 Parser" category = "main" optional = false -python-versions = "*" +python-versions = ">=3.6" [package.dependencies] -chardet = ">=4.0,<5.0" +chardet = ">=3.0,<5.0" PyYAML = ">=5.3,<6.0" requests = ">=2.25,<3.0" semver = ">=2.13,<3.0" @@ -420,7 +474,7 @@ six = ">=1.15,<2.0" [package.extras] cli = ["click (>=7.0,<8.0)"] -dev = ["tox (>=3.21)", "bumpversion (>=0.6)", "pytest (>=6.2)", "pytest-cov (>=2.11)", "flake8 (>=3.8)", "pep8-naming (>=0.11)", "flake8-quotes (>=3.2)", "flake8-docstrings (>=1.5)", "sphinx (>=3.4)", "towncrier (>=19.2)"] +dev = ["tox (>=3.21)", "bumpversion (>=0.6)", "pytest (>=6.1)", "pytest-cov (>=2.11)", "flake8 (>=3.8)", "pep8-naming (>=0.11)", "flake8-quotes (>=3.2)", "flake8-docstrings (>=1.5)", "sphinx (>=3.4)", "towncrier (>=19.2)"] flex = ["flex (>=6.13,<7.0)"] icu = ["PyICU (>=2.4,<3.0)"] osv = ["openapi-spec-validator (>=0.2.1)"] @@ -436,19 +490,19 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [[package]] name = "pydantic" -version = "1.7.3" +version = "1.8.2" description = "Data validation and settings management using python 3.6 type hinting" category = "main" optional = false -python-versions = ">=3.6" +python-versions = ">=3.6.1" [package.dependencies] email-validator = {version = ">=1.0.3", optional = true, markers = "extra == \"email\""} +typing-extensions = ">=3.7.4.3" [package.extras] dotenv = ["python-dotenv (>=0.10.4)"] email = ["email-validator (>=1.0.3)"] -typing_extensions = ["typing-extensions (>=3.7.2)"] [[package]] name = "pyparsing" @@ -460,11 +514,11 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "pyrsistent" -version = "0.17.3" +version = "0.18.0" description = "Persistent/Functional/Immutable data structures" category = "main" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" [[package]] name = "pysnooper" @@ -501,18 +555,19 @@ testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xm [[package]] name = "pytest-cov" -version = "2.12.0" +version = "2.12.1" description = "Pytest plugin for measuring coverage." category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" [package.dependencies] -coverage = {version = ">=5.2.1", extras = ["toml"]} +coverage = ">=5.2.1" pytest = ">=4.6" +toml = "*" [package.extras] -testing = ["fields", "hunter", "process-tests (==2.0.2)", "six", "pytest-xdist", "virtualenv"] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] [[package]] name = "pytest-mock" @@ -549,7 +604,7 @@ python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" [[package]] name = "regex" -version = "2020.11.13" +version = "2021.7.6" description = "Alternative regular expression module, to replace re." category = "main" optional = false @@ -605,7 +660,7 @@ python-versions = "!=3.0,!=3.1,!=3.2,!=3.3,>=2.6" [[package]] name = "six" -version = "1.15.0" +version = "1.16.0" description = "Python 2 and 3 compatibility utilities" category = "main" optional = false @@ -637,7 +692,7 @@ python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" [[package]] name = "typed-ast" -version = "1.4.2" +version = "1.4.3" description = "a fork of Python 2 and 3 ast modules with type comment support" category = "main" optional = false @@ -664,7 +719,7 @@ doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=5.4.0,<6.0.0)", "markdown- [[package]] name = "typing-extensions" -version = "3.7.4.3" +version = "3.10.0.0" description = "Backported and Experimental Type Hints for Python 3.5+" category = "main" optional = false @@ -672,58 +727,62 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.4" +version = "1.26.6" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" [package.extras] +brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] -brotli = ["brotlipy (>=0.6.0)"] [[package]] name = "zipp" -version = "3.4.0" +version = "3.5.0" description = "Backport of pathlib-compatible object wrapper for zip files" category = "main" optional = false python-versions = ">=3.6" [package.extras] -docs = ["sphinx", "jaraco.packaging (>=3.2)", "rst.linker (>=1.9)"] -testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake8", "pytest-cov", "jaraco.test (>=3.2.0)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] +docs = ["sphinx", "jaraco.packaging (>=8.2)", "rst.linker (>=1.9)"] +testing = ["pytest (>=4.6)", "pytest-checkdocs (>=2.4)", "pytest-flake8", "pytest-cov", "pytest-enabler (>=1.0.1)", "jaraco.itertools", "func-timeout", "pytest-black (>=0.3.7)", "pytest-mypy"] [metadata] lock-version = "1.1" python-versions = "^3.7.0" -content-hash = "5a5efa2e5172cd4d2fbc074ce8a51362473e6787c993eaeb6368fe8ef0e6988b" +content-hash = "9c0d565ab05f6c99e9bf88375112fd342e844aacbe58c7f68aa51af3f9e05a5e" [metadata.files] +anyio = [ + {file = "anyio-3.2.1-py3-none-any.whl", hash = "sha256:442678a3c7e1cdcdbc37dcfe4527aa851b1b0c9162653b516e9f509821691d50"}, + {file = "anyio-3.2.1.tar.gz", hash = "sha256:07968db9fa7c1ca5435a133dc62f988d84ef78e1d9b22814a59d1c62618afbc5"}, +] appdirs = [ {file = "appdirs-1.4.4-py2.py3-none-any.whl", hash = "sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128"}, {file = "appdirs-1.4.4.tar.gz", hash = "sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41"}, ] argcomplete = [ - {file = "argcomplete-1.12.2-py2.py3-none-any.whl", hash = "sha256:17f01a9b9b9ece3e6b07058eae737ad6e10de8b4e149105f84614783913aba71"}, - {file = "argcomplete-1.12.2.tar.gz", hash = "sha256:de0e1282330940d52ea92a80fea2e4b9e0da1932aaa570f84d268939d1897b04"}, + {file = "argcomplete-1.12.3-py2.py3-none-any.whl", hash = "sha256:291f0beca7fd49ce285d2f10e4c1c77e9460cf823eef2de54df0c0fec88b0d81"}, + {file = "argcomplete-1.12.3.tar.gz", hash = "sha256:2c7dbffd8c045ea534921e63b0be6fe65e88599990d8dc408ac8c542b72a5445"}, ] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, ] attrs = [ - {file = "attrs-20.3.0-py2.py3-none-any.whl", hash = "sha256:31b2eced602aa8423c2aea9c76a724617ed67cf9513173fd3a4f03e3a929c7e6"}, - {file = "attrs-20.3.0.tar.gz", hash = "sha256:832aa3cde19744e49938b91fea06d69ecb9e649c93ba974535d08ad92164f700"}, + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] black = [ {file = "black-19.10b0-py36-none-any.whl", hash = "sha256:1b30e59be925fafc1ee4565e5e08abef6b03fe455102883820fe5ee2e4734e0b"}, {file = "black-19.10b0.tar.gz", hash = "sha256:c2edb73a08e9e0e6f65a0e6af18b059b8b1cdd5bef997d7a0b181df93dc81539"}, ] certifi = [ - {file = "certifi-2020.12.5-py2.py3-none-any.whl", hash = "sha256:719a74fb9e33b9bd44cc7f3a8d94bc35e4049deebe19ba7d8e108280cfd59830"}, - {file = "certifi-2020.12.5.tar.gz", hash = "sha256:1a4995114262bffbc2413b159f2a1a480c969de6e6eb13ee966d470af86af59c"}, + {file = "certifi-2021.5.30-py2.py3-none-any.whl", hash = "sha256:50b1e4f8446b06f41be7dd6338db18e0990601dce795c2b1686458aa7e8fa7d8"}, + {file = "certifi-2021.5.30.tar.gz", hash = "sha256:2bbf76fd432960138b3ef6dda3dde0544f27cbf8546c458e60baf371917ba9ee"}, ] chardet = [ {file = "chardet-4.0.0-py2.py3-none-any.whl", hash = "sha256:f864054d66fd9118f2e67044ac8981a54775ec5b67aed0441892edb553d21da5"}, @@ -791,17 +850,14 @@ coverage = [ {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] -datamodel-code-generator = [ - {file = "datamodel-code-generator-0.11.6.tar.gz", hash = "sha256:18c3b416d7c43fc98248b42a29539a1729ac596aa2b490bf7b29a952c4728969"}, - {file = "datamodel_code_generator-0.11.6-py3-none-any.whl", hash = "sha256:e2ef31f89a136536b61bdb8862e7c1361b335da9f70b46cf62c17aa41c7a94a9"}, -] +datamodel-code-generator = [] dnspython = [ {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"}, {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, ] email-validator = [ - {file = "email-validator-1.1.2.tar.gz", hash = "sha256:1a13bd6050d1db4475f13e444e169b6fe872434922d38968c67cea9568cce2f0"}, - {file = "email_validator-1.1.2-py2.py3-none-any.whl", hash = "sha256:094b1d1c60d790649989d38d34f69e1ef07792366277a2cf88684d03495d018f"}, + {file = "email_validator-1.1.3-py2.py3-none-any.whl", hash = "sha256:5675c8ceb7106a37e40e2698a57c056756bf3f272cfa8682a4f87ebd95d8440b"}, + {file = "email_validator-1.1.3.tar.gz", hash = "sha256:aa237a65f6f4da067119b7df3f13e89c25c051327b2b5b66dc075f33d62480d7"}, ] freezegun = [ {file = "freezegun-1.1.0-py2.py3-none-any.whl", hash = "sha256:2ae695f7eb96c62529f03a038461afe3c692db3465e215355e1bb4b0ab408712"}, @@ -815,29 +871,33 @@ h11 = [ {file = "h11-0.12.0.tar.gz", hash = "sha256:47222cb6067e4a307d535814917cd98fd0a57b6788ce715755fa2b6c28b56042"}, ] httpcore = [ - {file = "httpcore-0.12.3-py3-none-any.whl", hash = "sha256:93e822cd16c32016b414b789aeff4e855d0ccbfc51df563ee34d4dbadbb3bcdc"}, - {file = "httpcore-0.12.3.tar.gz", hash = "sha256:37ae835fb370049b2030c3290e12ed298bf1473c41bb72ca4aa78681eba9b7c9"}, + {file = "httpcore-0.13.6-py3-none-any.whl", hash = "sha256:db4c0dcb8323494d01b8c6d812d80091a31e520033e7b0120883d6f52da649ff"}, + {file = "httpcore-0.13.6.tar.gz", hash = "sha256:b0d16f0012ec88d8cc848f5a55f8a03158405f4bca02ee49bc4ca2c1fda49f3e"}, ] httpx = [ - {file = "httpx-0.16.1-py3-none-any.whl", hash = "sha256:9cffb8ba31fac6536f2c8cde30df859013f59e4bcc5b8d43901cb3654a8e0a5b"}, - {file = "httpx-0.16.1.tar.gz", hash = "sha256:126424c279c842738805974687e0518a94c7ae8d140cd65b9c4f77ac46ffa537"}, + {file = "httpx-0.18.2-py3-none-any.whl", hash = "sha256:979afafecb7d22a1d10340bafb403cf2cb75aff214426ff206521fc79d26408c"}, + {file = "httpx-0.18.2.tar.gz", hash = "sha256:9f99c15d33642d38bce8405df088c1c4cfd940284b4290cacbfb02e64f4877c6"}, ] idna = [ {file = "idna-2.10-py2.py3-none-any.whl", hash = "sha256:b97d804b1e9b523befed77c48dacec60e6dcb0b5391d57af6a65a312a90648c0"}, {file = "idna-2.10.tar.gz", hash = "sha256:b307872f855b18632ce0c21c5e45be78c0ea7ae4c15c828c20788b26921eb3f6"}, ] importlib-metadata = [ - {file = "importlib_metadata-3.4.0-py3-none-any.whl", hash = "sha256:ace61d5fc652dc280e7b6b4ff732a9c2d40db2c0f92bc6cb74e07b73d53a1771"}, - {file = "importlib_metadata-3.4.0.tar.gz", hash = "sha256:fa5daa4477a7414ae34e95942e4dd07f62adf589143c875c133c1e53c4eff38d"}, + {file = "importlib_metadata-4.6.1-py3-none-any.whl", hash = "sha256:9f55f560e116f8643ecf2922d9cd3e1c7e8d52e683178fecd9d08f6aa357e11e"}, + {file = "importlib_metadata-4.6.1.tar.gz", hash = "sha256:079ada16b7fc30dfbb5d13399a5113110dab1aa7c2bc62f66af75f0b717c8cac"}, ] inflect = [ - {file = "inflect-4.1.1-py3-none-any.whl", hash = "sha256:b0d13bbb6e12313b8fc4a171c86c4f4544cf09a8498e118d25473558200bd171"}, - {file = "inflect-4.1.1.tar.gz", hash = "sha256:0527947406025991506b252620da69a5efdc72bf61aa6b4b4976e3bd71c19660"}, + {file = "inflect-5.3.0-py3-none-any.whl", hash = "sha256:42560be16af702a21d43d59427f276b5aed79efb1ded9b713468c081f4353d10"}, + {file = "inflect-5.3.0.tar.gz", hash = "sha256:41a23f6788962e9775e40e2ecfb1d6455d02de315022afeedd3c5dc070019d73"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +isodate = [ + {file = "isodate-0.6.0-py2.py3-none-any.whl", hash = "sha256:aa4d33c06640f5352aca96e4b81afd8ab3b47337cc12089822d6f322ac772c81"}, + {file = "isodate-0.6.0.tar.gz", hash = "sha256:2e364a3d5759479cdb2d37cce6b9376ea504db2ff90252a2e5b7cc89cc9ff2d8"}, +] isort = [ {file = "isort-4.3.21-py2.py3-none-any.whl", hash = "sha256:6e811fcb295968434526407adb8796944f1988c5b65e8139058f2014cbe100fd"}, {file = "isort-4.3.21.tar.gz", hash = "sha256:54da7e92468955c4fceacd0c86bd0ec997b0e1ee80d97f67c35a78b719dccab1"}, @@ -851,95 +911,83 @@ jsonschema = [ {file = "jsonschema-3.2.0.tar.gz", hash = "sha256:c8a85b28d377cc7737e46e2d9f2b4f44ee3c0e1deac6bf46ddefc7187d30797a"}, ] markupsafe = [ - {file = "MarkupSafe-1.1.1-cp27-cp27m-macosx_10_6_intel.whl", hash = "sha256:09027a7803a62ca78792ad89403b1b7a73a01c8cb65909cd876f7fcebd79b161"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:e249096428b3ae81b08327a63a485ad0878de3fb939049038579ac0ef61e17e7"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:500d4957e52ddc3351cabf489e79c91c17f6e0899158447047588650b5e69183"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win32.whl", hash = "sha256:b2051432115498d3562c084a49bba65d97cf251f5a331c64a12ee7e04dacc51b"}, - {file = "MarkupSafe-1.1.1-cp27-cp27m-win_amd64.whl", hash = "sha256:98c7086708b163d425c67c7a91bad6e466bb99d797aa64f965e9d25c12111a5e"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:cd5df75523866410809ca100dc9681e301e3c27567cf498077e8551b6d20e42f"}, - {file = "MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:43a55c2930bbc139570ac2452adf3d70cdbb3cfe5912c71cdce1c2c6bbd9c5d1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-macosx_10_6_intel.whl", hash = "sha256:1027c282dad077d0bae18be6794e6b6b8c91d58ed8a8d89a89d59693b9131db5"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_i686.whl", hash = "sha256:62fe6c95e3ec8a7fad637b7f3d372c15ec1caa01ab47926cfdf7a75b40e0eac1"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-manylinux1_x86_64.whl", hash = "sha256:88e5fcfb52ee7b911e8bb6d6aa2fd21fbecc674eadd44118a9cc3863f938e735"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win32.whl", hash = "sha256:ade5e387d2ad0d7ebf59146cc00c8044acbd863725f887353a10df825fc8ae21"}, - {file = "MarkupSafe-1.1.1-cp34-cp34m-win_amd64.whl", hash = "sha256:09c4b7f37d6c648cb13f9230d847adf22f8171b1ccc4d5682398e77f40309235"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-macosx_10_6_intel.whl", hash = "sha256:79855e1c5b8da654cf486b830bd42c06e8780cea587384cf6545b7d9ac013a0b"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:c8716a48d94b06bb3b2524c2b77e055fb313aeb4ea620c8dd03a105574ba704f"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:7c1699dfe0cf8ff607dbdcc1e9b9af1755371f92a68f706051cc8c37d447c905"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win32.whl", hash = "sha256:6dd73240d2af64df90aa7c4e7481e23825ea70af4b4922f8ede5b9e35f78a3b1"}, - {file = "MarkupSafe-1.1.1-cp35-cp35m-win_amd64.whl", hash = "sha256:9add70b36c5666a2ed02b43b335fe19002ee5235efd4b8a89bfcf9005bebac0d"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_6_intel.whl", hash = "sha256:24982cc2533820871eba85ba648cd53d8623687ff11cbb805be4ff7b4c971aff"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d53bc011414228441014aa71dbec320c66468c1030aae3a6e29778a3382d96e5"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:00bc623926325b26bb9605ae9eae8a215691f33cae5df11ca5424f06f2d1f473"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:717ba8fe3ae9cc0006d7c451f0bb265ee07739daf76355d06366154ee68d221e"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:3b8a6499709d29c2e2399569d96719a1b21dcd94410a586a18526b143ec8470f"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:84dee80c15f1b560d55bcfe6d47b27d070b4681c699c572af2e3c7cc90a3b8e0"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:b1dba4527182c95a0db8b6060cc98ac49b9e2f5e64320e2b56e47cb2831978c7"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win32.whl", hash = "sha256:535f6fc4d397c1563d08b88e485c3496cf5784e927af890fb3c3aac7f933ec66"}, - {file = "MarkupSafe-1.1.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b1282f8c00509d99fef04d8ba936b156d419be841854fe901d8ae224c59f0be5"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_6_intel.whl", hash = "sha256:8defac2f2ccd6805ebf65f5eeb132adcf2ab57aa11fdf4c0dd5169a004710e7d"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:bf5aa3cbcfdf57fa2ee9cd1822c862ef23037f5c832ad09cfea57fa846dec193"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:46c99d2de99945ec5cb54f23c8cd5689f6d7177305ebff350a58ce5f8de1669e"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:ba59edeaa2fc6114428f1637ffff42da1e311e29382d81b339c1817d37ec93c6"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:6fffc775d90dcc9aed1b89219549b329a9250d918fd0b8fa8d93d154918422e1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:a6a744282b7718a2a62d2ed9d993cad6f5f585605ad352c11de459f4108df0a1"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:195d7d2c4fbb0ee8139a6cf67194f3973a6b3042d742ebe0a9ed36d8b6f0c07f"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win32.whl", hash = "sha256:b00c1de48212e4cc9603895652c5c410df699856a2853135b3967591e4beebc2"}, - {file = "MarkupSafe-1.1.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9bf40443012702a1d2070043cb6291650a0841ece432556f784f004937f0f32c"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6788b695d50a51edb699cb55e35487e430fa21f1ed838122d722e0ff0ac5ba15"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:cdb132fc825c38e1aeec2c8aa9338310d29d337bebbd7baa06889d09a60a1fa2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:13d3144e1e340870b25e7b10b98d779608c02016d5184cfb9927a9f10c689f42"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:acf08ac40292838b3cbbb06cfe9b2cb9ec78fce8baca31ddb87aaac2e2dc3bc2"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:d9be0ba6c527163cbed5e0857c451fcd092ce83947944d6c14bc95441203f032"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:caabedc8323f1e93231b52fc32bdcde6db817623d33e100708d9a68e1f53b26b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win32.whl", hash = "sha256:596510de112c685489095da617b5bcbbac7dd6384aeebeda4df6025d0256a81b"}, - {file = "MarkupSafe-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:e8313f01ba26fbbe36c7be1966a7b7424942f670f38e666995b88d012765b9be"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d73a845f227b0bfe8a7455ee623525ee656a9e2e749e4742706d80a6065d5e2c"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:98bae9582248d6cf62321dcb52aaf5d9adf0bad3b40582925ef7c7f0ed85fceb"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:2beec1e0de6924ea551859edb9e7679da6e4870d32cb766240ce17e0a0ba2014"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:7fed13866cf14bba33e7176717346713881f56d9d2bcebab207f7a036f41b850"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:6f1e273a344928347c1290119b493a1f0303c52f5a5eae5f16d74f48c15d4a85"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:feb7b34d6325451ef96bc0e36e1a6c0c1c64bc1fbec4b854f4529e51887b1621"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win32.whl", hash = "sha256:22c178a091fc6630d0d045bdb5992d2dfe14e3259760e713c490da5323866c39"}, - {file = "MarkupSafe-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:b7d644ddb4dbd407d31ffb699f1d140bc35478da613b441c582aeb7c43838dd8"}, - {file = "MarkupSafe-1.1.1.tar.gz", hash = "sha256:29872e92839765e546828bb7754a68c418d927cd064fd4708fab9fe9c8bb116b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f9081981fe268bd86831e5c75f7de206ef275defcb82bc70740ae6dc507aee51"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:0955295dd5eec6cb6cc2fe1698f4c6d84af2e92de33fbcac4111913cd100a6ff"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:0446679737af14f45767963a1a9ef7620189912317d095f2d9ffa183a4d25d2b"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:f826e31d18b516f653fe296d967d700fddad5901ae07c622bb3705955e1faa94"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:fa130dd50c57d53368c9d59395cb5526eda596d3ffe36666cd81a44d56e48872"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:905fec760bd2fa1388bb5b489ee8ee5f7291d692638ea5f67982d968366bef9f"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win32.whl", hash = "sha256:6c4ca60fa24e85fe25b912b01e62cb969d69a23a5d5867682dd3e80b5b02581d"}, + {file = "MarkupSafe-2.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:b2f4bf27480f5e5e8ce285a8c8fd176c0b03e93dcc6646477d4630e83440c6a9"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0717a7390a68be14b8c793ba258e075c6f4ca819f15edfc2a3a027c823718567"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:6557b31b5e2c9ddf0de32a691f2312a32f77cd7681d8af66c2692efdbef84c18"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:49e3ceeabbfb9d66c3aef5af3a60cc43b85c33df25ce03d0031a608b0a8b2e3f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:d7f9850398e85aba693bb640262d3611788b1f29a79f0c93c565694658f4071f"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:6a7fae0dd14cf60ad5ff42baa2e95727c3d81ded453457771d02b7d2b3f9c0c2"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:b7f2d075102dc8c794cbde1947378051c4e5180d52d276987b8d28a3bd58c17d"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win32.whl", hash = "sha256:a30e67a65b53ea0a5e62fe23682cfe22712e01f453b95233b25502f7c61cb415"}, + {file = "MarkupSafe-2.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:611d1ad9a4288cf3e3c16014564df047fe08410e628f89805e475368bd304914"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:be98f628055368795d818ebf93da628541e10b75b41c559fdf36d104c5787066"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:1d609f577dc6e1aa17d746f8bd3c31aa4d258f4070d61b2aa5c4166c1539de35"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7d91275b0245b1da4d4cfa07e0faedd5b0812efc15b702576d103293e252af1b"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:01a9b8ea66f1658938f65b93a85ebe8bc016e6769611be228d797c9d998dd298"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:47ab1e7b91c098ab893b828deafa1203de86d0bc6ab587b160f78fe6c4011f75"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:97383d78eb34da7e1fa37dd273c20ad4320929af65d156e35a5e2d89566d9dfb"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win32.whl", hash = "sha256:023cb26ec21ece8dc3907c0e8320058b2e0cb3c55cf9564da612bc325bed5e64"}, + {file = "MarkupSafe-2.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:984d76483eb32f1bcb536dc27e4ad56bba4baa70be32fa87152832cdd9db0833"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2ef54abee730b502252bcdf31b10dacb0a416229b72c18b19e24a4509f273d26"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3c112550557578c26af18a1ccc9e090bfe03832ae994343cfdacd287db6a6ae7"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_i686.whl", hash = "sha256:53edb4da6925ad13c07b6d26c2a852bd81e364f95301c66e930ab2aef5b5ddd8"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:f5653a225f31e113b152e56f154ccbe59eeb1c7487b39b9d9f9cdb58e6c79dc5"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:4efca8f86c54b22348a5467704e3fec767b2db12fc39c6d963168ab1d3fc9135"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:ab3ef638ace319fa26553db0624c4699e31a28bb2a835c5faca8f8acf6a5a902"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:f8ba0e8349a38d3001fae7eadded3f6606f0da5d748ee53cc1dab1d6527b9509"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win32.whl", hash = "sha256:10f82115e21dc0dfec9ab5c0223652f7197feb168c940f3ef61563fc2d6beb74"}, + {file = "MarkupSafe-2.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:693ce3f9e70a6cf7d2fb9e6c9d8b204b6b39897a2c4a1aa65728d5ac97dcc1d8"}, + {file = "MarkupSafe-2.0.1.tar.gz", hash = "sha256:594c67807fb16238b30c44bdf74f36c02cdf22d1c8cda91ef8a0ed8dabf5620a"}, ] mypy = [ - {file = "mypy-0.812-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49"}, - {file = "mypy-0.812-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c"}, - {file = "mypy-0.812-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521"}, - {file = "mypy-0.812-cp35-cp35m-win_amd64.whl", hash = "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb"}, - {file = "mypy-0.812-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a"}, - {file = "mypy-0.812-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c"}, - {file = "mypy-0.812-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6"}, - {file = "mypy-0.812-cp36-cp36m-win_amd64.whl", hash = "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064"}, - {file = "mypy-0.812-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56"}, - {file = "mypy-0.812-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8"}, - {file = "mypy-0.812-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7"}, - {file = "mypy-0.812-cp37-cp37m-win_amd64.whl", hash = "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564"}, - {file = "mypy-0.812-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506"}, - {file = "mypy-0.812-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5"}, - {file = "mypy-0.812-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66"}, - {file = "mypy-0.812-cp38-cp38-win_amd64.whl", hash = "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e"}, - {file = "mypy-0.812-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a"}, - {file = "mypy-0.812-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a"}, - {file = "mypy-0.812-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97"}, - {file = "mypy-0.812-cp39-cp39-win_amd64.whl", hash = "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df"}, - {file = "mypy-0.812-py3-none-any.whl", hash = "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4"}, - {file = "mypy-0.812.tar.gz", hash = "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119"}, + {file = "mypy-0.910-cp35-cp35m-macosx_10_9_x86_64.whl", hash = "sha256:a155d80ea6cee511a3694b108c4494a39f42de11ee4e61e72bc424c490e46457"}, + {file = "mypy-0.910-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:b94e4b785e304a04ea0828759172a15add27088520dc7e49ceade7834275bedb"}, + {file = "mypy-0.910-cp35-cp35m-manylinux2010_x86_64.whl", hash = "sha256:088cd9c7904b4ad80bec811053272986611b84221835e079be5bcad029e79dd9"}, + {file = "mypy-0.910-cp35-cp35m-win_amd64.whl", hash = "sha256:adaeee09bfde366d2c13fe6093a7df5df83c9a2ba98638c7d76b010694db760e"}, + {file = "mypy-0.910-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:ecd2c3fe726758037234c93df7e98deb257fd15c24c9180dacf1ef829da5f921"}, + {file = "mypy-0.910-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:d9dd839eb0dc1bbe866a288ba3c1afc33a202015d2ad83b31e875b5905a079b6"}, + {file = "mypy-0.910-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:3e382b29f8e0ccf19a2df2b29a167591245df90c0b5a2542249873b5c1d78212"}, + {file = "mypy-0.910-cp36-cp36m-win_amd64.whl", hash = "sha256:53fd2eb27a8ee2892614370896956af2ff61254c275aaee4c230ae771cadd885"}, + {file = "mypy-0.910-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b6fb13123aeef4a3abbcfd7e71773ff3ff1526a7d3dc538f3929a49b42be03f0"}, + {file = "mypy-0.910-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:e4dab234478e3bd3ce83bac4193b2ecd9cf94e720ddd95ce69840273bf44f6de"}, + {file = "mypy-0.910-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:7df1ead20c81371ccd6091fa3e2878559b5c4d4caadaf1a484cf88d93ca06703"}, + {file = "mypy-0.910-cp37-cp37m-win_amd64.whl", hash = "sha256:0aadfb2d3935988ec3815952e44058a3100499f5be5b28c34ac9d79f002a4a9a"}, + {file = "mypy-0.910-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:ec4e0cd079db280b6bdabdc807047ff3e199f334050db5cbb91ba3e959a67504"}, + {file = "mypy-0.910-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:119bed3832d961f3a880787bf621634ba042cb8dc850a7429f643508eeac97b9"}, + {file = "mypy-0.910-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:866c41f28cee548475f146aa4d39a51cf3b6a84246969f3759cb3e9c742fc072"}, + {file = "mypy-0.910-cp38-cp38-win_amd64.whl", hash = "sha256:ceb6e0a6e27fb364fb3853389607cf7eb3a126ad335790fa1e14ed02fba50811"}, + {file = "mypy-0.910-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1a85e280d4d217150ce8cb1a6dddffd14e753a4e0c3cf90baabb32cefa41b59e"}, + {file = "mypy-0.910-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:42c266ced41b65ed40a282c575705325fa7991af370036d3f134518336636f5b"}, + {file = "mypy-0.910-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:3c4b8ca36877fc75339253721f69603a9c7fdb5d4d5a95a1a1b899d8b86a4de2"}, + {file = "mypy-0.910-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:c0df2d30ed496a08de5daed2a9ea807d07c21ae0ab23acf541ab88c24b26ab97"}, + {file = "mypy-0.910-cp39-cp39-win_amd64.whl", hash = "sha256:c6c2602dffb74867498f86e6129fd52a2770c48b7cd3ece77ada4fa38f94eba8"}, + {file = "mypy-0.910-py3-none-any.whl", hash = "sha256:ef565033fa5a958e62796867b1df10c40263ea9ded87164d67572834e57a174d"}, + {file = "mypy-0.910.tar.gz", hash = "sha256:704098302473cb31a218f1775a873b376b30b4c18229421e9e9dc8916fd16150"}, ] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +openapi-schema-validator = [ + {file = "openapi-schema-validator-0.1.5.tar.gz", hash = "sha256:a4b2712020284cee880b4c55faa513fbc2f8f07f365deda6098f8ab943c9f0df"}, + {file = "openapi_schema_validator-0.1.5-py2-none-any.whl", hash = "sha256:215b516d0942f4e8e2446cf3f7d4ff2ed71d102ebddcc30526d8a3f706ab1df6"}, + {file = "openapi_schema_validator-0.1.5-py3-none-any.whl", hash = "sha256:b65d6c2242620bfe76d4c749b61cd9657e4528895a8f4fb6f916085b508ebd24"}, +] openapi-spec-validator = [ - {file = "openapi-spec-validator-0.2.9.tar.gz", hash = "sha256:79381a69b33423ee400ae1624a461dae7725e450e2e306e32f2dd8d16a4d85cb"}, - {file = "openapi_spec_validator-0.2.9-py2-none-any.whl", hash = "sha256:6dd75e50c94f1bb454d0e374a56418e7e06a07affb2c7f1df88564c5d728dac3"}, - {file = "openapi_spec_validator-0.2.9-py3-none-any.whl", hash = "sha256:ec1b01a00e20955a527358886991ae34b4b791b253027ee9f7df5f84b59d91c7"}, + {file = "openapi-spec-validator-0.3.1.tar.gz", hash = "sha256:3d70e6592754799f7e77a45b98c6a91706bdd309a425169d17d8e92173e198a2"}, + {file = "openapi_spec_validator-0.3.1-py2-none-any.whl", hash = "sha256:0a7da925bad4576f4518f77302c0b1990adb2fbcbe7d63fb4ed0de894cad8bdd"}, + {file = "openapi_spec_validator-0.3.1-py3-none-any.whl", hash = "sha256:ba28b06e63274f2bc6de995a07fb572c657e534425b5baf68d9f7911efe6929f"}, ] packaging = [ - {file = "packaging-20.9-py2.py3-none-any.whl", hash = "sha256:67714da7f7bc052e064859c05c595155bd1ee9f69f76557e21f051443c20947a"}, - {file = "packaging-20.9.tar.gz", hash = "sha256:5b327ac1320dc863dca72f4514ecc086f31186744b84a230374cc1fd776feae5"}, + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] pathspec = [ {file = "pathspec-0.8.1-py2.py3-none-any.whl", hash = "sha256:aa0cb481c4041bf52ffa7b0d8fa6cd3e88a2ca4879c533c9153882ee2556790d"}, @@ -950,43 +998,63 @@ pluggy = [ {file = "pluggy-0.13.1.tar.gz", hash = "sha256:15b2acde666561e1298d71b523007ed7364de07029219b604cf808bfa1c765b0"}, ] prance = [ - {file = "prance-0.20.2-py2.py3-none-any.whl", hash = "sha256:dc79bf29af07d630e7d8119bad8440ab85aed49ada5a0705f08e469afeffa35f"}, - {file = "prance-0.20.2.tar.gz", hash = "sha256:4ffcddae6218cf6753a02af36ca9fb1c92eec4689441789ee2e9963230882388"}, + {file = "prance-0.21.2-py3-none-any.whl", hash = "sha256:03374b020a4f643c71fc941bb7d1e4852331732714b4b6ebbbd53dd5f75adacf"}, + {file = "prance-0.21.2.tar.gz", hash = "sha256:43ebe3a5b38f0c65c428427004c4d8ce8d7155ddad50610276c89c192680f138"}, ] py = [ {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, ] pydantic = [ - {file = "pydantic-1.7.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c59ea046aea25be14dc22d69c97bee629e6d48d2b2ecb724d7fe8806bf5f61cd"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a4143c8d0c456a093387b96e0f5ee941a950992904d88bc816b4f0e72c9a0009"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:d8df4b9090b595511906fa48deda47af04e7d092318bfb291f4d45dfb6bb2127"}, - {file = "pydantic-1.7.3-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:514b473d264671a5c672dfb28bdfe1bf1afd390f6b206aa2ec9fed7fc592c48e"}, - {file = "pydantic-1.7.3-cp36-cp36m-win_amd64.whl", hash = "sha256:dba5c1f0a3aeea5083e75db9660935da90216f8a81b6d68e67f54e135ed5eb23"}, - {file = "pydantic-1.7.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59e45f3b694b05a69032a0d603c32d453a23f0de80844fb14d55ab0c6c78ff2f"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:5b24e8a572e4b4c18f614004dda8c9f2c07328cb5b6e314d6e1bbd536cb1a6c1"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:b2b054d095b6431cdda2f852a6d2f0fdec77686b305c57961b4c5dd6d863bf3c"}, - {file = "pydantic-1.7.3-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:025bf13ce27990acc059d0c5be46f416fc9b293f45363b3d19855165fee1874f"}, - {file = "pydantic-1.7.3-cp37-cp37m-win_amd64.whl", hash = "sha256:6e3874aa7e8babd37b40c4504e3a94cc2023696ced5a0500949f3347664ff8e2"}, - {file = "pydantic-1.7.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:e682f6442ebe4e50cb5e1cfde7dda6766fb586631c3e5569f6aa1951fd1a76ef"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:185e18134bec5ef43351149fe34fda4758e53d05bb8ea4d5928f0720997b79ef"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:f5b06f5099e163295b8ff5b1b71132ecf5866cc6e7f586d78d7d3fd6e8084608"}, - {file = "pydantic-1.7.3-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:24ca47365be2a5a3cc3f4a26dcc755bcdc9f0036f55dcedbd55663662ba145ec"}, - {file = "pydantic-1.7.3-cp38-cp38-win_amd64.whl", hash = "sha256:d1fe3f0df8ac0f3a9792666c69a7cd70530f329036426d06b4f899c025aca74e"}, - {file = "pydantic-1.7.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f6864844b039805add62ebe8a8c676286340ba0c6d043ae5dea24114b82a319e"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:ecb54491f98544c12c66ff3d15e701612fc388161fd455242447083350904730"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:ffd180ebd5dd2a9ac0da4e8b995c9c99e7c74c31f985ba090ee01d681b1c4b95"}, - {file = "pydantic-1.7.3-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8d72e814c7821125b16f1553124d12faba88e85405b0864328899aceaad7282b"}, - {file = "pydantic-1.7.3-cp39-cp39-win_amd64.whl", hash = "sha256:475f2fa134cf272d6631072554f845d0630907fce053926ff634cc6bc45bf1af"}, - {file = "pydantic-1.7.3-py3-none-any.whl", hash = "sha256:38be427ea01a78206bcaf9a56f835784afcba9e5b88fbdce33bbbfbcd7841229"}, - {file = "pydantic-1.7.3.tar.gz", hash = "sha256:213125b7e9e64713d16d988d10997dabc6a1f73f3991e1ff8e35ebb1409c7dc9"}, + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, ] pyparsing = [ {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, ] pyrsistent = [ - {file = "pyrsistent-0.17.3.tar.gz", hash = "sha256:2e636185d9eb976a18a8a8e96efce62f2905fea90041958d8cc2a189756ebf3e"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f4c8cabb46ff8e5d61f56a037974228e978f26bfefce4f61a4b1ac0ba7a2ab72"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:da6e5e818d18459fa46fac0a4a4e543507fe1110e808101277c5a2b5bab0cd2d"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:5e4395bbf841693eaebaa5bb5c8f5cdbb1d139e07c975c682ec4e4f8126e03d2"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win32.whl", hash = "sha256:527be2bfa8dc80f6f8ddd65242ba476a6c4fb4e3aedbf281dfbac1b1ed4165b1"}, + {file = "pyrsistent-0.18.0-cp36-cp36m-win_amd64.whl", hash = "sha256:2aaf19dc8ce517a8653746d98e962ef480ff34b6bc563fc067be6401ffb457c7"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58a70d93fb79dc585b21f9d72487b929a6fe58da0754fa4cb9f279bb92369396"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:4916c10896721e472ee12c95cdc2891ce5890898d2f9907b1b4ae0f53588b710"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:73ff61b1411e3fb0ba144b8f08d6749749775fe89688093e1efef9839d2dcc35"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win32.whl", hash = "sha256:b29b869cf58412ca5738d23691e96d8aff535e17390128a1a52717c9a109da4f"}, + {file = "pyrsistent-0.18.0-cp37-cp37m-win_amd64.whl", hash = "sha256:097b96f129dd36a8c9e33594e7ebb151b1515eb52cceb08474c10a5479e799f2"}, + {file = "pyrsistent-0.18.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:772e94c2c6864f2cd2ffbe58bb3bdefbe2a32afa0acb1a77e472aac831f83427"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_i686.whl", hash = "sha256:c1a9ff320fa699337e05edcaae79ef8c2880b52720bc031b219e5b5008ebbdef"}, + {file = "pyrsistent-0.18.0-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cd3caef37a415fd0dae6148a1b6957a8c5f275a62cca02e18474608cb263640c"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win32.whl", hash = "sha256:e79d94ca58fcafef6395f6352383fa1a76922268fa02caa2272fff501c2fdc78"}, + {file = "pyrsistent-0.18.0-cp38-cp38-win_amd64.whl", hash = "sha256:a0c772d791c38bbc77be659af29bb14c38ced151433592e326361610250c605b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d5ec194c9c573aafaceebf05fc400656722793dac57f254cd4741f3c27ae57b4"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_i686.whl", hash = "sha256:6b5eed00e597b5b5773b4ca30bd48a5774ef1e96f2a45d105db5b4ebb4bca680"}, + {file = "pyrsistent-0.18.0-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:48578680353f41dca1ca3dc48629fb77dfc745128b56fc01096b2530c13fd426"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win32.whl", hash = "sha256:f3ef98d7b76da5eb19c37fda834d50262ff9167c65658d1d8f974d2e4d90676b"}, + {file = "pyrsistent-0.18.0-cp39-cp39-win_amd64.whl", hash = "sha256:404e1f1d254d314d55adb8d87f4f465c8693d6f902f67eb6ef5b4526dc58e6ea"}, + {file = "pyrsistent-0.18.0.tar.gz", hash = "sha256:773c781216f8c2900b42a7b638d5b517bb134ae1acbebe4d1e8f1f41ea60eb4b"}, ] pysnooper = [ {file = "PySnooper-0.5.0-py2.py3-none-any.whl", hash = "sha256:7280fd86cd1da732fade981e00998bf01be39e9e4a58b418469f47203cc329b1"}, @@ -997,8 +1065,8 @@ pytest = [ {file = "pytest-6.2.4.tar.gz", hash = "sha256:50bcad0a0b9c5a72c8e4e7c9855a3ad496ca6a881a3641b4260605450772c54b"}, ] pytest-cov = [ - {file = "pytest-cov-2.12.0.tar.gz", hash = "sha256:8535764137fecce504a49c2b742288e3d34bc09eed298ad65963616cc98fd45e"}, - {file = "pytest_cov-2.12.0-py2.py3-none-any.whl", hash = "sha256:95d4933dcbbacfa377bb60b29801daa30d90c33981ab2a79e9ab4452c165066e"}, + {file = "pytest-cov-2.12.1.tar.gz", hash = "sha256:261ceeb8c227b726249b376b8526b600f38667ee314f910353fa318caa01f4d7"}, + {file = "pytest_cov-2.12.1-py2.py3-none-any.whl", hash = "sha256:261bb9e47e65bd099c89c3edf92972865210c36813f80ede5277dceb77a4a62a"}, ] pytest-mock = [ {file = "pytest-mock-3.6.1.tar.gz", hash = "sha256:40217a058c52a63f1042f0784f62009e976ba824c418cced42e88d5f40ab0e62"}, @@ -1040,47 +1108,47 @@ pyyaml = [ {file = "PyYAML-5.4.1.tar.gz", hash = "sha256:607774cbba28732bfa802b54baa7484215f530991055bb562efbed5b2f20a45e"}, ] regex = [ - {file = "regex-2020.11.13-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:8b882a78c320478b12ff024e81dc7d43c1462aa4a3341c754ee65d857a521f85"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a63f1a07932c9686d2d416fb295ec2c01ab246e89b4d58e5fa468089cab44b70"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:6e4b08c6f8daca7d8f07c8d24e4331ae7953333dbd09c648ed6ebd24db5a10ee"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:bba349276b126947b014e50ab3316c027cac1495992f10e5682dc677b3dfa0c5"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:56e01daca75eae420bce184edd8bb341c8eebb19dd3bce7266332258f9fb9dd7"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:6a8ce43923c518c24a2579fda49f093f1397dad5d18346211e46f134fc624e31"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:1ab79fcb02b930de09c76d024d279686ec5d532eb814fd0ed1e0051eb8bd2daa"}, - {file = "regex-2020.11.13-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:9801c4c1d9ae6a70aeb2128e5b4b68c45d4f0af0d1535500884d644fa9b768c6"}, - {file = "regex-2020.11.13-cp36-cp36m-win32.whl", hash = "sha256:49cae022fa13f09be91b2c880e58e14b6da5d10639ed45ca69b85faf039f7a4e"}, - {file = "regex-2020.11.13-cp36-cp36m-win_amd64.whl", hash = "sha256:749078d1eb89484db5f34b4012092ad14b327944ee7f1c4f74d6279a6e4d1884"}, - {file = "regex-2020.11.13-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b2f4007bff007c96a173e24dcda236e5e83bde4358a557f9ccf5e014439eae4b"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:38c8fd190db64f513fe4e1baa59fed086ae71fa45083b6936b52d34df8f86a88"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5862975b45d451b6db51c2e654990c1820523a5b07100fc6903e9c86575202a0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:262c6825b309e6485ec2493ffc7e62a13cf13fb2a8b6d212f72bd53ad34118f1"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:bafb01b4688833e099d79e7efd23f99172f501a15c44f21ea2118681473fdba0"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:e32f5f3d1b1c663af7f9c4c1e72e6ffe9a78c03a31e149259f531e0fed826512"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:3bddc701bdd1efa0d5264d2649588cbfda549b2899dc8d50417e47a82e1387ba"}, - {file = "regex-2020.11.13-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:02951b7dacb123d8ea6da44fe45ddd084aa6777d4b2454fa0da61d569c6fa538"}, - {file = "regex-2020.11.13-cp37-cp37m-win32.whl", hash = "sha256:0d08e71e70c0237883d0bef12cad5145b84c3705e9c6a588b2a9c7080e5af2a4"}, - {file = "regex-2020.11.13-cp37-cp37m-win_amd64.whl", hash = "sha256:1fa7ee9c2a0e30405e21031d07d7ba8617bc590d391adfc2b7f1e8b99f46f444"}, - {file = "regex-2020.11.13-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:baf378ba6151f6e272824b86a774326f692bc2ef4cc5ce8d5bc76e38c813a55f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e3faaf10a0d1e8e23a9b51d1900b72e1635c2d5b0e1bea1c18022486a8e2e52d"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:2a11a3e90bd9901d70a5b31d7dd85114755a581a5da3fc996abfefa48aee78af"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:d1ebb090a426db66dd80df8ca85adc4abfcbad8a7c2e9a5ec7513ede522e0a8f"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:b2b1a5ddae3677d89b686e5c625fc5547c6e492bd755b520de5332773a8af06b"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:2c99e97d388cd0a8d30f7c514d67887d8021541b875baf09791a3baad48bb4f8"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:c084582d4215593f2f1d28b65d2a2f3aceff8342aa85afd7be23a9cad74a0de5"}, - {file = "regex-2020.11.13-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:a3d748383762e56337c39ab35c6ed4deb88df5326f97a38946ddd19028ecce6b"}, - {file = "regex-2020.11.13-cp38-cp38-win32.whl", hash = "sha256:7913bd25f4ab274ba37bc97ad0e21c31004224ccb02765ad984eef43e04acc6c"}, - {file = "regex-2020.11.13-cp38-cp38-win_amd64.whl", hash = "sha256:6c54ce4b5d61a7129bad5c5dc279e222afd00e721bf92f9ef09e4fae28755683"}, - {file = "regex-2020.11.13-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:1862a9d9194fae76a7aaf0150d5f2a8ec1da89e8b55890b1786b8f88a0f619dc"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4902e6aa086cbb224241adbc2f06235927d5cdacffb2425c73e6570e8d862364"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:7a25fcbeae08f96a754b45bdc050e1fb94b95cab046bf56b016c25e9ab127b3e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:d2d8ce12b7c12c87e41123997ebaf1a5767a5be3ec545f64675388970f415e2e"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f7d29a6fc4760300f86ae329e3b6ca28ea9c20823df123a2ea8693e967b29917"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:717881211f46de3ab130b58ec0908267961fadc06e44f974466d1887f865bd5b"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:3128e30d83f2e70b0bed9b2a34e92707d0877e460b402faca908c6667092ada9"}, - {file = "regex-2020.11.13-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:8f6a2229e8ad946e36815f2a03386bb8353d4bde368fdf8ca5f0cb97264d3b5c"}, - {file = "regex-2020.11.13-cp39-cp39-win32.whl", hash = "sha256:f8f295db00ef5f8bae530fc39af0b40486ca6068733fb860b42115052206466f"}, - {file = "regex-2020.11.13-cp39-cp39-win_amd64.whl", hash = "sha256:a15f64ae3a027b64496a71ab1f722355e570c3fac5ba2801cafce846bf5af01d"}, - {file = "regex-2020.11.13.tar.gz", hash = "sha256:83d6b356e116ca119db8e7c6fc2983289d87b27b3fac238cfe5dca529d884562"}, + {file = "regex-2021.7.6-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e6a1e5ca97d411a461041d057348e578dc344ecd2add3555aedba3b408c9f874"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:6afe6a627888c9a6cfbb603d1d017ce204cebd589d66e0703309b8048c3b0854"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:ccb3d2190476d00414aab36cca453e4596e8f70a206e2aa8db3d495a109153d2"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_i686.whl", hash = "sha256:ed693137a9187052fc46eedfafdcb74e09917166362af4cc4fddc3b31560e93d"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2010_x86_64.whl", hash = "sha256:99d8ab206a5270c1002bfcf25c51bf329ca951e5a169f3b43214fdda1f0b5f0d"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:b85ac458354165405c8a84725de7bbd07b00d9f72c31a60ffbf96bb38d3e25fa"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:3f5716923d3d0bfb27048242a6e0f14eecdb2e2a7fac47eda1d055288595f222"}, + {file = "regex-2021.7.6-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5983c19d0beb6af88cb4d47afb92d96751fb3fa1784d8785b1cdf14c6519407"}, + {file = "regex-2021.7.6-cp36-cp36m-win32.whl", hash = "sha256:c92831dac113a6e0ab28bc98f33781383fe294df1a2c3dfd1e850114da35fd5b"}, + {file = "regex-2021.7.6-cp36-cp36m-win_amd64.whl", hash = "sha256:791aa1b300e5b6e5d597c37c346fb4d66422178566bbb426dd87eaae475053fb"}, + {file = "regex-2021.7.6-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:59506c6e8bd9306cd8a41511e32d16d5d1194110b8cfe5a11d102d8b63cf945d"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:564a4c8a29435d1f2256ba247a0315325ea63335508ad8ed938a4f14c4116a5d"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:59c00bb8dd8775473cbfb967925ad2c3ecc8886b3b2d0c90a8e2707e06c743f0"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_i686.whl", hash = "sha256:9a854b916806c7e3b40e6616ac9e85d3cdb7649d9e6590653deb5b341a736cec"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2010_x86_64.whl", hash = "sha256:db2b7df831c3187a37f3bb80ec095f249fa276dbe09abd3d35297fc250385694"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:173bc44ff95bc1e96398c38f3629d86fa72e539c79900283afa895694229fe6a"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:15dddb19823f5147e7517bb12635b3c82e6f2a3a6b696cc3e321522e8b9308ad"}, + {file = "regex-2021.7.6-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ddeabc7652024803666ea09f32dd1ed40a0579b6fbb2a213eba590683025895"}, + {file = "regex-2021.7.6-cp37-cp37m-win32.whl", hash = "sha256:f080248b3e029d052bf74a897b9d74cfb7643537fbde97fe8225a6467fb559b5"}, + {file = "regex-2021.7.6-cp37-cp37m-win_amd64.whl", hash = "sha256:d8bbce0c96462dbceaa7ac4a7dfbbee92745b801b24bce10a98d2f2b1ea9432f"}, + {file = "regex-2021.7.6-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:edd1a68f79b89b0c57339bce297ad5d5ffcc6ae7e1afdb10f1947706ed066c9c"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux1_i686.whl", hash = "sha256:422dec1e7cbb2efbbe50e3f1de36b82906def93ed48da12d1714cabcd993d7f0"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:cbe23b323988a04c3e5b0c387fe3f8f363bf06c0680daf775875d979e376bd26"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2010_i686.whl", hash = "sha256:0eb2c6e0fcec5e0f1d3bcc1133556563222a2ffd2211945d7b1480c1b1a42a6f"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2010_x86_64.whl", hash = "sha256:1c78780bf46d620ff4fff40728f98b8afd8b8e35c3efd638c7df67be2d5cddbf"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:bc84fb254a875a9f66616ed4538542fb7965db6356f3df571d783f7c8d256edd"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:598c0a79b4b851b922f504f9f39a863d83ebdfff787261a5ed061c21e67dd761"}, + {file = "regex-2021.7.6-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875c355360d0f8d3d827e462b29ea7682bf52327d500a4f837e934e9e4656068"}, + {file = "regex-2021.7.6-cp38-cp38-win32.whl", hash = "sha256:e586f448df2bbc37dfadccdb7ccd125c62b4348cb90c10840d695592aa1b29e0"}, + {file = "regex-2021.7.6-cp38-cp38-win_amd64.whl", hash = "sha256:2fe5e71e11a54e3355fa272137d521a40aace5d937d08b494bed4529964c19c4"}, + {file = "regex-2021.7.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6110bab7eab6566492618540c70edd4d2a18f40ca1d51d704f1d81c52d245026"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux1_i686.whl", hash = "sha256:4f64fc59fd5b10557f6cd0937e1597af022ad9b27d454e182485f1db3008f417"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:89e5528803566af4df368df2d6f503c84fbfb8249e6631c7b025fe23e6bd0cde"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2010_i686.whl", hash = "sha256:2366fe0479ca0e9afa534174faa2beae87847d208d457d200183f28c74eaea59"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2010_x86_64.whl", hash = "sha256:f9392a4555f3e4cb45310a65b403d86b589adc773898c25a39184b1ba4db8985"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:2bceeb491b38225b1fee4517107b8491ba54fba77cf22a12e996d96a3c55613d"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:f98dc35ab9a749276f1a4a38ab3e0e2ba1662ce710f6530f5b0a6656f1c32b58"}, + {file = "regex-2021.7.6-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:319eb2a8d0888fa6f1d9177705f341bc9455a2c8aca130016e52c7fe8d6c37a3"}, + {file = "regex-2021.7.6-cp39-cp39-win32.whl", hash = "sha256:eaf58b9e30e0e546cdc3ac06cf9165a1ca5b3de8221e9df679416ca667972035"}, + {file = "regex-2021.7.6-cp39-cp39-win_amd64.whl", hash = "sha256:4c9c3155fe74269f61e27617529b7f09552fbb12e44b1189cebbdb24294e6e1c"}, + {file = "regex-2021.7.6.tar.gz", hash = "sha256:8394e266005f2d8c6f0bc6780001f7afa3ef81a7a2111fa35058ded6fce79e4d"}, ] requests = [ {file = "requests-2.25.1-py2.py3-none-any.whl", hash = "sha256:c210084e36a42ae6b9219e00e48287def368a26d03a048ddad7bfee44f75871e"}, @@ -1099,8 +1167,8 @@ shellingham = [ {file = "shellingham-1.4.0.tar.gz", hash = "sha256:4855c2458d6904829bd34c299f11fdeed7cfefbf8a2c522e4caea6cd76b3171e"}, ] six = [ - {file = "six-1.15.0-py2.py3-none-any.whl", hash = "sha256:8b74bedcbbbaca38ff6d7491d76f2b06b3592611af620f8426e82dddb04a5ced"}, - {file = "six-1.15.0.tar.gz", hash = "sha256:30639c035cdb23534cd4aa2dd52c3bf48f06e5f4a941509c8bafd8ce11080259"}, + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, ] sniffio = [ {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, @@ -1114,51 +1182,51 @@ toml = [ {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, ] typed-ast = [ - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:7703620125e4fb79b64aa52427ec192822e9f45d37d4b6625ab37ef403e1df70"}, - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c9aadc4924d4b5799112837b226160428524a9a45f830e0d0f184b19e4090487"}, - {file = "typed_ast-1.4.2-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:9ec45db0c766f196ae629e509f059ff05fc3148f9ffd28f3cfe75d4afb485412"}, - {file = "typed_ast-1.4.2-cp35-cp35m-win32.whl", hash = "sha256:85f95aa97a35bdb2f2f7d10ec5bbdac0aeb9dafdaf88e17492da0504de2e6400"}, - {file = "typed_ast-1.4.2-cp35-cp35m-win_amd64.whl", hash = "sha256:9044ef2df88d7f33692ae3f18d3be63dec69c4fb1b5a4a9ac950f9b4ba571606"}, - {file = "typed_ast-1.4.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:c1c876fd795b36126f773db9cbb393f19808edd2637e00fd6caba0e25f2c7b64"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:5dcfc2e264bd8a1db8b11a892bd1647154ce03eeba94b461effe68790d8b8e07"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:8db0e856712f79c45956da0c9a40ca4246abc3485ae0d7ecc86a20f5e4c09abc"}, - {file = "typed_ast-1.4.2-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:d003156bb6a59cda9050e983441b7fa2487f7800d76bdc065566b7d728b4581a"}, - {file = "typed_ast-1.4.2-cp36-cp36m-win32.whl", hash = "sha256:4c790331247081ea7c632a76d5b2a265e6d325ecd3179d06e9cf8d46d90dd151"}, - {file = "typed_ast-1.4.2-cp36-cp36m-win_amd64.whl", hash = "sha256:d175297e9533d8d37437abc14e8a83cbc68af93cc9c1c59c2c292ec59a0697a3"}, - {file = "typed_ast-1.4.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:cf54cfa843f297991b7388c281cb3855d911137223c6b6d2dd82a47ae5125a41"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:b4fcdcfa302538f70929eb7b392f536a237cbe2ed9cba88e3bf5027b39f5f77f"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:987f15737aba2ab5f3928c617ccf1ce412e2e321c77ab16ca5a293e7bbffd581"}, - {file = "typed_ast-1.4.2-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:37f48d46d733d57cc70fd5f30572d11ab8ed92da6e6b28e024e4a3edfb456e37"}, - {file = "typed_ast-1.4.2-cp37-cp37m-win32.whl", hash = "sha256:36d829b31ab67d6fcb30e185ec996e1f72b892255a745d3a82138c97d21ed1cd"}, - {file = "typed_ast-1.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:8368f83e93c7156ccd40e49a783a6a6850ca25b556c0fa0240ed0f659d2fe496"}, - {file = "typed_ast-1.4.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:963c80b583b0661918718b095e02303d8078950b26cc00b5e5ea9ababe0de1fc"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e683e409e5c45d5c9082dc1daf13f6374300806240719f95dc783d1fc942af10"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:84aa6223d71012c68d577c83f4e7db50d11d6b1399a9c779046d75e24bed74ea"}, - {file = "typed_ast-1.4.2-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:a38878a223bdd37c9709d07cd357bb79f4c760b29210e14ad0fb395294583787"}, - {file = "typed_ast-1.4.2-cp38-cp38-win32.whl", hash = "sha256:a2c927c49f2029291fbabd673d51a2180038f8cd5a5b2f290f78c4516be48be2"}, - {file = "typed_ast-1.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:c0c74e5579af4b977c8b932f40a5464764b2f86681327410aa028a22d2f54937"}, - {file = "typed_ast-1.4.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:07d49388d5bf7e863f7fa2f124b1b1d89d8aa0e2f7812faff0a5658c01c59aa1"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:240296b27397e4e37874abb1df2a608a92df85cf3e2a04d0d4d61055c8305ba6"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:d746a437cdbca200622385305aedd9aef68e8a645e385cc483bdc5e488f07166"}, - {file = "typed_ast-1.4.2-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:14bf1522cdee369e8f5581238edac09150c765ec1cb33615855889cf33dcb92d"}, - {file = "typed_ast-1.4.2-cp39-cp39-win32.whl", hash = "sha256:cc7b98bf58167b7f2db91a4327da24fb93368838eb84a44c472283778fc2446b"}, - {file = "typed_ast-1.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:7147e2a76c75f0f64c4319886e7639e490fee87c9d25cb1d4faef1d8cf83a440"}, - {file = "typed_ast-1.4.2.tar.gz", hash = "sha256:9fc0b3cb5d1720e7141d103cf4819aea239f7d136acf9ee4a69b047b7986175a"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_i686.whl", hash = "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux1_x86_64.whl", hash = "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075"}, + {file = "typed_ast-1.4.3-cp35-cp35m-manylinux2014_aarch64.whl", hash = "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win32.whl", hash = "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428"}, + {file = "typed_ast-1.4.3-cp35-cp35m-win_amd64.whl", hash = "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3"}, + {file = "typed_ast-1.4.3-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace"}, + {file = "typed_ast-1.4.3-cp36-cp36m-manylinux2014_aarch64.whl", hash = "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win32.whl", hash = "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363"}, + {file = "typed_ast-1.4.3-cp36-cp36m-win_amd64.whl", hash = "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7"}, + {file = "typed_ast-1.4.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04"}, + {file = "typed_ast-1.4.3-cp37-cp37m-manylinux2014_aarch64.whl", hash = "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win32.whl", hash = "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c"}, + {file = "typed_ast-1.4.3-cp37-cp37m-win_amd64.whl", hash = "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805"}, + {file = "typed_ast-1.4.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_i686.whl", hash = "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41"}, + {file = "typed_ast-1.4.3-cp38-cp38-manylinux2014_aarch64.whl", hash = "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39"}, + {file = "typed_ast-1.4.3-cp38-cp38-win32.whl", hash = "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927"}, + {file = "typed_ast-1.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40"}, + {file = "typed_ast-1.4.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_i686.whl", hash = "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux1_x86_64.whl", hash = "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0"}, + {file = "typed_ast-1.4.3-cp39-cp39-manylinux2014_aarch64.whl", hash = "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3"}, + {file = "typed_ast-1.4.3-cp39-cp39-win32.whl", hash = "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808"}, + {file = "typed_ast-1.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c"}, + {file = "typed_ast-1.4.3.tar.gz", hash = "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65"}, ] typer = [ {file = "typer-0.3.2-py3-none-any.whl", hash = "sha256:ba58b920ce851b12a2d790143009fa00ac1d05b3ff3257061ff69dbdfc3d161b"}, {file = "typer-0.3.2.tar.gz", hash = "sha256:5455d750122cff96745b0dec87368f56d023725a7ebc9d2e54dd23dc86816303"}, ] typing-extensions = [ - {file = "typing_extensions-3.7.4.3-py2-none-any.whl", hash = "sha256:dafc7639cde7f1b6e1acc0f457842a83e722ccca8eef5270af2d74792619a89f"}, - {file = "typing_extensions-3.7.4.3-py3-none-any.whl", hash = "sha256:7cb407020f00f7bfc3cb3e7881628838e69d8f3fcab2f64742a5e76b2f841918"}, - {file = "typing_extensions-3.7.4.3.tar.gz", hash = "sha256:99d4073b617d30288f569d3f13d2bd7548c3a7e4c8de87db09a9d29bb3a4a60c"}, + {file = "typing_extensions-3.10.0.0-py2-none-any.whl", hash = "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497"}, + {file = "typing_extensions-3.10.0.0-py3-none-any.whl", hash = "sha256:779383f6086d90c99ae41cf0ff39aac8a7937a9283ce0a414e5dd782f4c94a84"}, + {file = "typing_extensions-3.10.0.0.tar.gz", hash = "sha256:50b6f157849174217d0656f99dc82fe932884fb250826c18350e159ec6cdf342"}, ] urllib3 = [ - {file = "urllib3-1.26.4-py2.py3-none-any.whl", hash = "sha256:2f4da4594db7e1e110a944bb1b551fdf4e6c136ad42e4234131391e21eb5b0df"}, - {file = "urllib3-1.26.4.tar.gz", hash = "sha256:e7b021f7241115872f92f43c6508082facffbd1c048e3c6e2bb9c2a157e28937"}, + {file = "urllib3-1.26.6-py2.py3-none-any.whl", hash = "sha256:39fb8672126159acb139a7718dd10806104dec1e2f0f6c88aab05d17df10c8d4"}, + {file = "urllib3-1.26.6.tar.gz", hash = "sha256:f57b4c16c62fa2760b7e3d97c35b255512fb6b59a259730f36ba32ce9f8e342f"}, ] zipp = [ - {file = "zipp-3.4.0-py3-none-any.whl", hash = "sha256:102c24ef8f171fd729d46599845e95c7ab894a4cf45f5de11a44cc7444fb1108"}, - {file = "zipp-3.4.0.tar.gz", hash = "sha256:ed5eee1974372595f9e416cc7bbeeb12335201d8081ca8a0743c954d4446e5cb"}, + {file = "zipp-3.5.0-py3-none-any.whl", hash = "sha256:957cfda87797e389580cb8b9e3870841ca991e2125350677b2ca83a0e99390a3"}, + {file = "zipp-3.5.0.tar.gz", hash = "sha256:f5812b1e007e48cff63449a5e9f4e7ebea716b4111f9c4f9a645f91d579bf0c4"}, ] diff --git a/pyproject.toml b/pyproject.toml index 053c1d4..8fca6b2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ fastapi-codegen = "fastapi_code_generator.__main__:app" [tool.poetry.dependencies] python = "^3.7.0" typer = {extras = ["all"], version = ">=0.2.1,<0.4.0"} -datamodel-code-generator = {extras = ["http"], version = "^0.11.3"} +datamodel-code-generator = {extras = ["http"], git = "https://github.com/koxudaxi/datamodel-code-generator.git", branch = "improve_openapi_parser" } stringcase = "^1.2.0" PySnooper = ">=0.4.1,<0.6.0" jinja2 = "^2.11.2" diff --git a/tests/data/expected/openapi/default_template/body_and_parameters/models.py b/tests/data/expected/openapi/default_template/body_and_parameters/models.py index 6541a8d..a620e3e 100644 --- a/tests/data/expected/openapi/default_template/body_and_parameters/models.py +++ b/tests/data/expected/openapi/default_template/body_and_parameters/models.py @@ -10,6 +10,22 @@ from pydantic import BaseModel +class Pet(BaseModel): + id: int + name: str + tag: Optional[str] = None + + +class Error(BaseModel): + code: int + message: str + + +class PetForm(BaseModel): + name: Optional[str] = None + age: Optional[int] = None + + class UserGetResponse(BaseModel): timestamp: datetime name: str @@ -32,19 +48,3 @@ class UsersPostRequest(BaseModel): timestamp: datetime name: str age: Optional[str] = None - - -class Pet(BaseModel): - id: int - name: str - tag: Optional[str] = None - - -class Error(BaseModel): - code: int - message: str - - -class PetForm(BaseModel): - name: Optional[str] = None - age: Optional[int] = None From a1f9f659f7972048ad19a7b68f69430ff428a9b7 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sun, 18 Jul 2021 00:53:20 +0900 Subject: [PATCH 07/13] update datamodel-code-generator --- poetry.lock | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/poetry.lock b/poetry.lock index 00df130..c63fa81 100644 --- a/poetry.lock +++ b/poetry.lock @@ -107,11 +107,12 @@ toml = ["toml"] [[package]] name = "datamodel-code-generator" -version = "0.11.8" +version = "0.11.9.dev9+g317b434" description = "Datamodel Code Generator" category = "main" optional = false python-versions = ">=3.6.1" +develop = false [package.dependencies] argcomplete = ">=1.10,<2.0" @@ -139,6 +140,12 @@ setup = ["pytest-runner", "setuptools-scm"] test = ["pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml"] wheel = ["wheel", "twine"] +[package.source] +type = "git" +url = "https://github.com/koxudaxi/datamodel-code-generator.git" +reference = "improve_openapi_parser" +resolved_reference = "317b434c72b69dd7616d99d50a1d44851eda3c9c" + [[package]] name = "dnspython" version = "2.1.0" @@ -698,7 +705,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7.0" -content-hash = "5a5efa2e5172cd4d2fbc074ce8a51362473e6787c993eaeb6368fe8ef0e6988b" +content-hash = "9c0d565ab05f6c99e9bf88375112fd342e844aacbe58c7f68aa51af3f9e05a5e" [metadata.files] appdirs = [ @@ -791,10 +798,7 @@ coverage = [ {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] -datamodel-code-generator = [ - {file = "datamodel-code-generator-0.11.8.tar.gz", hash = "sha256:5d5d654f4811d3e029fab118a5188337da72e5aea1dfc9d6a689327cfb988171"}, - {file = "datamodel_code_generator-0.11.8-py3-none-any.whl", hash = "sha256:cd0a90bc81612e1b04b7b60e9321c73dc4e1122f05eaa657e645a03ed41be6c0"}, -] +datamodel-code-generator = [] dnspython = [ {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"}, {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, From cfe52195c37b8bd45b8ebc2866de79d8ba15eac5 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sun, 18 Jul 2021 00:55:23 +0900 Subject: [PATCH 08/13] fix broken marge --- fastapi_code_generator/parser.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index ec2397b..fe10f34 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -379,9 +379,6 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] if request: arguments.append(request) - if self.request: - arguments.append(self.request) - positional_argument: bool = False for argument in arguments: if positional_argument and argument.required and argument.default is None: From 0e48fbe778afc785a9c41c2392080f83d61bbd59 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sun, 18 Jul 2021 01:34:07 +0900 Subject: [PATCH 09/13] Improve __main__.py --- fastapi_code_generator/__main__.py | 51 +++++++++++++----------------- fastapi_code_generator/parser.py | 37 ++-------------------- 2 files changed, 24 insertions(+), 64 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 71f6c15..e9ce117 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -1,17 +1,16 @@ from datetime import datetime, timezone from pathlib import Path -from typing import Dict, Optional +from typing import Dict, List, Optional import typer from datamodel_code_generator import PythonVersion, chdir from datamodel_code_generator.format import CodeFormatter -from datamodel_code_generator.imports import Import -from datamodel_code_generator.parser.openapi import OpenAPIParser as OpenAPIModelParser +from datamodel_code_generator.imports import Import, Imports from datamodel_code_generator.reference import Reference from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader -from fastapi_code_generator.parser import MODEL_PATH, OpenAPIParser, ParsedObject +from fastapi_code_generator.parser import MODEL_PATH, OpenAPIParser, Operation app = typer.Typer() @@ -47,12 +46,16 @@ def generate_code( if not template_dir: template_dir = BUILTIN_TEMPLATE_DIR - # model_parser = OpenAPIModelParser(source=input_text,) - parser = OpenAPIParser(input_text) - # parsed_object: ParsedObject = parser.parse() - models = parser.parse() - parsed_object = parser.parse_paths() + with chdir(output_dir): + models = parser.parse() + if not models: + return + elif isinstance(models, str): + output = output_dir / MODEL_PATH + modules = {output: (models, input_name)} + else: + raise Exception('Modular references are not supported in this version') environment: Environment = Environment( loader=FileSystemLoader( @@ -60,24 +63,24 @@ def generate_code( encoding="utf8", ), ) - parsed_object.imports.update(parser.imports) + imports = Imports() + imports.update(parser.imports) for data_type in parser.data_types: reference = _get_most_of_reference(data_type) if reference: - parsed_object.imports.append(data_type.all_imports) - parsed_object.imports.append( - Import.from_full_path(f'.models.{reference.name}') - ) - for from_, imports in parser.imports_for_fastapi.items(): - parsed_object.imports[from_].update(imports) + imports.append(data_type.all_imports) + imports.append(Import.from_full_path(f'.models.{reference.name}')) + for from_, imports_ in parser.imports_for_fastapi.items(): + imports[from_].update(imports_) results: Dict[Path, str] = {} code_formatter = CodeFormatter(PythonVersion.PY_38, Path().resolve()) + sorted_operations: List[Operation] = sorted( + parser.operations.values(), key=lambda m: m.path + ) for target in template_dir.rglob("*"): relative_path = target.relative_to(template_dir) result = environment.get_template(str(relative_path)).render( - operations=parsed_object.operations, - imports=parsed_object.imports, - info=parsed_object.info, + operations=sorted_operations, imports=imports, info=parser.parse_info(), ) results[relative_path] = code_formatter.format_code(result) @@ -93,16 +96,6 @@ def generate_code( print("", file=file) print(code.rstrip(), file=file) - # with chdir(output_dir): - # results = parser.parse() - if not models: - return - elif isinstance(models, str): - output = output_dir / MODEL_PATH - modules = {output: (models, input_name)} - else: - raise Exception('Modular references are not supported in this version') - header = f'''\ # generated by fastapi-codegen: # filename: {{filename}}''' diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index fe10f34..6ee7b7e 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -174,33 +174,6 @@ def function_name(self) -> str: return stringcase.snakecase(name) -OPERATION_NAMES: List[str] = [ - "get", - "put", - "post", - "delete", - "patch", - "head", - "options", - "trace", -] - - -class ParsedObject: - def __init__( - self, - parsed_operations: List[Operation], - info: Optional[List[Dict[str, Any]]] = None, - ): - self.operations: List[Operation] = sorted( - parsed_operations, key=lambda m: m.path - ) - self.imports: Imports = Imports() - self.info = info - for operation in self.operations: - self.imports.append(operation.imports) - - @snooper_to_methods(max_variable_length=None) class OpenAPIParser(OpenAPIModelParser): def __init__( @@ -290,10 +263,8 @@ def __init__( self.imports_for_fastapi: Imports = Imports() self.data_types: List[DataType] = [] - def parse_info( - self, openapi: Dict[str, Any] - ) -> Optional[List[Dict[str, List[str]]]]: - return openapi.get('info') + def parse_info(self) -> Optional[List[Dict[str, List[str]]]]: + return self.raw_obj.get('info') def parse_parameters(self, parameters: ParameterObject, path: List[str]) -> None: super().parse_parameters(parameters, path) @@ -471,7 +442,3 @@ def parse_operation(self, raw_operation: Dict[str, Any], path: List[str],) -> No path=f'/{path_name}', # type: ignore method=method, # type: ignore ) - - def parse_paths(self) -> ParsedObject: - info = self.parse_info(self.raw_obj) - return ParsedObject(list(self.operations.values()), info,) From 8c8e79df84f98bca04501e479675a8c06a438ca5 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Mon, 19 Jul 2021 00:00:22 +0900 Subject: [PATCH 10/13] remove unneeded variables --- fastapi_code_generator/__main__.py | 8 ++++++-- fastapi_code_generator/parser.py | 32 +----------------------------- 2 files changed, 7 insertions(+), 33 deletions(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index e9ce117..b42a783 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -10,12 +10,14 @@ from datamodel_code_generator.types import DataType from jinja2 import Environment, FileSystemLoader -from fastapi_code_generator.parser import MODEL_PATH, OpenAPIParser, Operation +from fastapi_code_generator.parser import OpenAPIParser, Operation app = typer.Typer() BUILTIN_TEMPLATE_DIR = Path(__file__).parent / "template" +MODEL_PATH: Path = Path("models.py") + @app.command() def main( @@ -69,7 +71,9 @@ def generate_code( reference = _get_most_of_reference(data_type) if reference: imports.append(data_type.all_imports) - imports.append(Import.from_full_path(f'.models.{reference.name}')) + imports.append( + Import.from_full_path(f'.{MODEL_PATH.stem}.{reference.name}') + ) for from_, imports_ in parser.imports_for_fastapi.items(): imports[from_].update(imports_) results: Dict[Path, str] = {} diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 6ee7b7e..11f208d 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -2,7 +2,6 @@ import pathlib import re -from contextvars import ContextVar from typing import ( Any, Callable, @@ -33,10 +32,7 @@ from datamodel_code_generator.model import DataModel, DataModelFieldBase from datamodel_code_generator.model import pydantic as pydantic_model from datamodel_code_generator.model.pydantic import DataModelField -from datamodel_code_generator.parser.jsonschema import ( - JsonSchemaObject, - get_model_by_path, -) +from datamodel_code_generator.parser.jsonschema import JsonSchemaObject from datamodel_code_generator.parser.openapi import MediaObject from datamodel_code_generator.parser.openapi import OpenAPIParser as OpenAPIModelParser from datamodel_code_generator.parser.openapi import ( @@ -48,30 +44,9 @@ from datamodel_code_generator.types import DataType, DataTypeManager, StrictTypes from pydantic import BaseModel -MODEL_PATH: pathlib.Path = pathlib.Path("models.py") - -model_module_name_var: ContextVar[str] = ContextVar( - 'model_module_name', default=f'.{MODEL_PATH.stem}' -) - RE_APPLICATION_JSON_PATTERN: Pattern[str] = re.compile(r'^application/.*json$') -def get_ref_body( - ref: str, openapi_model_parser: OpenAPIModelParser, components: Dict[str, Any] -) -> Dict[str, Any]: - if ref.startswith('#/components'): - return get_model_by_path(components, ref[13:].split('/')) - elif ref.startswith('http://') or ref.startswith('https://'): - if '#/' in ref: - url, path = ref.rsplit('#/', 1) - ref_body = openapi_model_parser._get_ref_body(url) - return get_model_by_path(ref_body, path.split('/')) - else: - return openapi_model_parser._get_ref_body(ref) - raise NotImplementedError(f'ref={ref} is not supported') - - class CachedPropertyModel(BaseModel): class Config: arbitrary_types_allowed = True @@ -136,10 +111,8 @@ class Operation(CachedPropertyModel): summary: Optional[str] parameters: List[Dict[str, Any]] = [] responses: Dict[UsefulStr, Any] = {} - # requestBody: Dict[str, Any] = {} imports: List[Import] = [] security: Optional[List[Dict[str, List[str]]]] = None - # components: Dict[str, Any] = {} tags: Optional[List[str]] arguments: str = '' snake_case_arguments: str = '' @@ -215,7 +188,6 @@ def __init__( custom_class_name_generator: Optional[Callable[[str], str]] = None, field_extra_keys: Optional[Set[str]] = None, field_include_all_keys: bool = False, - model_module_name: Optional[str] = None, ): super().__init__( source=source, @@ -256,8 +228,6 @@ def __init__( field_include_all_keys=field_include_all_keys, openapi_scopes=[OpenAPIScope.Schemas, OpenAPIScope.Paths], ) - if model_module_name: - model_module_name_var.set(model_module_name) self.operations: Dict[str, Operation] = {} self._temporary_operation_items: Dict[str, Any] = {} self.imports_for_fastapi: Imports = Imports() From 571e1682ae38563e1e3cf6aa33ac8416c717a345 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Sat, 24 Jul 2021 00:09:56 +0900 Subject: [PATCH 11/13] Improve parsing parameters --- fastapi_code_generator/parser.py | 79 ++++++++++++++------------------ 1 file changed, 35 insertions(+), 44 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 11f208d..dcb29cf 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -36,6 +36,7 @@ from datamodel_code_generator.parser.openapi import MediaObject from datamodel_code_generator.parser.openapi import OpenAPIParser as OpenAPIModelParser from datamodel_code_generator.parser.openapi import ( + ParameterLocation, ParameterObject, ReferenceObject, RequestBodyObject, @@ -229,7 +230,7 @@ def __init__( openapi_scopes=[OpenAPIScope.Schemas, OpenAPIScope.Paths], ) self.operations: Dict[str, Operation] = {} - self._temporary_operation_items: Dict[str, Any] = {} + self._temporary_operation: Dict[str, Any] = {} self.imports_for_fastapi: Imports = Imports() self.data_types: List[DataType] = [] @@ -238,55 +239,47 @@ def parse_info(self) -> Optional[List[Dict[str, List[str]]]]: def parse_parameters(self, parameters: ParameterObject, path: List[str]) -> None: super().parse_parameters(parameters, path) + self._temporary_operation['_parameters'].append(parameters) def get_parameter_type( - self, - parameter: Dict[str, Union[str, Dict[str, Any]]], - snake_case: bool, - path: List[str], + self, parameters: ParameterObject, snake_case: bool, path: List[str], ) -> Argument: - ref: Optional[str] = parameter.get('$ref') # type: ignore - if ref: - parameter = self.get_ref_model(ref) - name: str = parameter["name"] # type: ignore - orig_name = name + orig_name = parameters.name if snake_case: - name = stringcase.snakecase(name) - content = parameter.get('content') + name = stringcase.snakecase(parameters.name) + else: + name = parameters.name + schema: Optional[JsonSchemaObject] = None - if content and isinstance(content, dict): - content_schema = [ - c.get("schema") - for c in content.values() - if isinstance(c.get("schema"), dict) - ] - if content_schema: - schema = JsonSchemaObject.parse_obj(content_schema[0]) - if not schema: - schema = JsonSchemaObject.parse_obj(parameter["schema"]) + data_type: Optional[DataType] = None + for content in parameters.content.values(): + if isinstance(content.schema_, ReferenceObject): + data_type = self.get_ref_data_type(content.schema_.ref) + ref_model = self.get_ref_model(content.schema_.ref) + schema = JsonSchemaObject.parse_obj(ref_model) + else: + schema = content.schema_ + break + if not data_type: + if not schema: + schema = parameters.schema_ + self.parse_schema(name, schema, [*path, name]) field = DataModelField( name=name, - data_type=self.parse_schema(name, schema, [*path, name]), - required=parameter.get("required") or parameter.get("in") == "path", + data_type=data_type, + required=parameters.required or parameters.in_ == ParameterLocation.path, ) if orig_name != name: - has_in = parameter.get('in') - if has_in and isinstance(has_in, str): - param_is = has_in.lower().capitalize() + if parameters.in_: + param_is = parameters.in_.value.lower().capitalize() self.imports_for_fastapi.append( Import(from_='fastapi', import_=param_is) ) default: Optional[ str ] = f"{param_is}({'...' if field.required else repr(schema.default)}, alias='{orig_name}')" - else: - # https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#parameterObject - # the spec says 'in' is a str type - raise TypeError( - f'Issue processing parameter for "in", expected a str, but got something else: {str(parameter)}' - ) else: default = repr(schema.default) if schema.has_default else None self.imports_for_fastapi.append(field.imports) @@ -307,7 +300,7 @@ def get_arguments(self, snake_case: bool, path: List[str]) -> str: def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument]: arguments: List[Argument] = [] - parameters = self._temporary_operation_items.get('_parameters') + parameters = self._temporary_operation.get('_parameters') if parameters: for parameter in parameters: arguments.append( @@ -316,7 +309,7 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] ) ) - request = self._temporary_operation_items.get('_request') + request = self._temporary_operation.get('_request') if request: arguments.append(request) @@ -369,9 +362,7 @@ def parse_request_body( self.imports_for_fastapi.append( Import.from_full_path('starlette.requests.Request') ) - self._temporary_operation_items['_request'] = ( - arguments[0] if arguments else None - ) + self._temporary_operation['_request'] = arguments[0] if arguments else None def parse_responses( self, @@ -388,27 +379,27 @@ def parse_responses( type_hint = data_type.type_hint # TODO: change to lazy loading else: type_hint = 'None' - self._temporary_operation_items['response'] = type_hint + self._temporary_operation['response'] = type_hint return data_types def parse_operation(self, raw_operation: Dict[str, Any], path: List[str],) -> None: - self._temporary_operation_items = {} + self._temporary_operation = {} + self._temporary_operation['_parameters'] = [] super().parse_operation(raw_operation, path) resolved_path = self.model_resolver.resolve_ref(path) path_name, method = path[-2:] - self._temporary_operation_items['_parameters'] = raw_operation.get('parameters') - self._temporary_operation_items['arguments'] = self.get_arguments( + self._temporary_operation['arguments'] = self.get_arguments( snake_case=False, path=path ) - self._temporary_operation_items['snake_case_arguments'] = self.get_arguments( + self._temporary_operation['snake_case_arguments'] = self.get_arguments( snake_case=True, path=path ) self.operations[resolved_path] = Operation( **raw_operation, - **self._temporary_operation_items, + **self._temporary_operation, path=f'/{path_name}', # type: ignore method=method, # type: ignore ) From 369e0c91253536c02d08c31631071fac2cf69f5b Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Mon, 2 Aug 2021 02:35:16 +0900 Subject: [PATCH 12/13] Update datamodel-code-generator version --- fastapi_code_generator/parser.py | 12 +++++++----- poetry.lock | 22 ++++++++-------------- pyproject.toml | 2 +- 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index dcb29cf..2db2222 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -243,7 +243,7 @@ def parse_parameters(self, parameters: ParameterObject, path: List[str]) -> None def get_parameter_type( self, parameters: ParameterObject, snake_case: bool, path: List[str], - ) -> Argument: + ) -> Optional[Argument]: orig_name = parameters.name if snake_case: name = stringcase.snakecase(parameters.name) @@ -264,6 +264,8 @@ def get_parameter_type( if not schema: schema = parameters.schema_ self.parse_schema(name, schema, [*path, name]) + if not schema: + return None field = DataModelField( name=name, @@ -303,11 +305,11 @@ def get_argument_list(self, snake_case: bool, path: List[str]) -> List[Argument] parameters = self._temporary_operation.get('_parameters') if parameters: for parameter in parameters: - arguments.append( - self.get_parameter_type( - parameter, snake_case, [*path, 'parameters'] - ) + parameter_type = self.get_parameter_type( + parameter, snake_case, [*path, 'parameters'] ) + if parameter_type: + arguments.append(parameter_type) request = self._temporary_operation.get('_request') if request: diff --git a/poetry.lock b/poetry.lock index c63fa81..05a00a1 100644 --- a/poetry.lock +++ b/poetry.lock @@ -107,12 +107,11 @@ toml = ["toml"] [[package]] name = "datamodel-code-generator" -version = "0.11.9.dev9+g317b434" +version = "0.11.9" description = "Datamodel Code Generator" category = "main" optional = false python-versions = ">=3.6.1" -develop = false [package.dependencies] argcomplete = ">=1.10,<2.0" @@ -121,7 +120,7 @@ genson = ">=1.2.1,<2.0" httpx = {version = "*", optional = true, markers = "extra == \"http\""} inflect = ">=4.1.0,<6.0" isort = ">=4.3.21,<6.0" -jinja2 = ">=2.10.1,<3.0" +jinja2 = ">=2.10.1,<4.0" openapi-spec-validator = ">=0.2.8,<0.4" prance = ">=0.18.2,<1.0" pydantic = [ @@ -132,19 +131,11 @@ PySnooper = ">=0.4.1,<1.0.0" toml = ">=0.10.0,<1.0.0" [package.extras] -all = ["pytest-runner", "setuptools-scm", "pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml", "httpx", "mkdocs", "mkdocs-material", "wheel", "twine", "codecov"] +all = ["pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml", "httpx", "mkdocs", "mkdocs-material", "codecov"] ci = ["codecov"] docs = ["mkdocs", "mkdocs-material"] http = ["httpx"] -setup = ["pytest-runner", "setuptools-scm"] test = ["pytest (>=4.6)", "pytest-benchmark", "pytest-cov", "pytest-mock", "mypy", "isort", "freezegun", "types-jinja2", "types-pyyaml", "types-toml"] -wheel = ["wheel", "twine"] - -[package.source] -type = "git" -url = "https://github.com/koxudaxi/datamodel-code-generator.git" -reference = "improve_openapi_parser" -resolved_reference = "317b434c72b69dd7616d99d50a1d44851eda3c9c" [[package]] name = "dnspython" @@ -705,7 +696,7 @@ testing = ["pytest (>=3.5,!=3.7.3)", "pytest-checkdocs (>=1.2.3)", "pytest-flake [metadata] lock-version = "1.1" python-versions = "^3.7.0" -content-hash = "9c0d565ab05f6c99e9bf88375112fd342e844aacbe58c7f68aa51af3f9e05a5e" +content-hash = "7337c9af1ae3d342cc84e66833886b60522b778e5fcd6b8372d17d7695c189de" [metadata.files] appdirs = [ @@ -798,7 +789,10 @@ coverage = [ {file = "coverage-5.5-pp37-none-any.whl", hash = "sha256:2a3859cb82dcbda1cfd3e6f71c27081d18aa251d20a17d87d26d4cd216fb0af4"}, {file = "coverage-5.5.tar.gz", hash = "sha256:ebe78fe9a0e874362175b02371bdfbee64d8edc42a044253ddf4ee7d3c15212c"}, ] -datamodel-code-generator = [] +datamodel-code-generator = [ + {file = "datamodel-code-generator-0.11.9.tar.gz", hash = "sha256:ee65eaef77be2f366093a7efb1a89940af7dae892606081d8442ecd1dd9c7a6a"}, + {file = "datamodel_code_generator-0.11.9-py3-none-any.whl", hash = "sha256:419860f753b394ffc542d5af764f1db0c8ac4231707a14863ed5bd18a7d1c04e"}, +] dnspython = [ {file = "dnspython-2.1.0-py3-none-any.whl", hash = "sha256:95d12f6ef0317118d2a1a6fc49aac65ffec7eb8087474158f42f26a639135216"}, {file = "dnspython-2.1.0.zip", hash = "sha256:e4a87f0b573201a0f3727fa18a516b055fd1107e0e5477cded4a2de497df1dd4"}, diff --git a/pyproject.toml b/pyproject.toml index 8fca6b2..ea8eb2a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -30,7 +30,7 @@ fastapi-codegen = "fastapi_code_generator.__main__:app" [tool.poetry.dependencies] python = "^3.7.0" typer = {extras = ["all"], version = ">=0.2.1,<0.4.0"} -datamodel-code-generator = {extras = ["http"], git = "https://github.com/koxudaxi/datamodel-code-generator.git", branch = "improve_openapi_parser" } +datamodel-code-generator = {extras = ["http"], version = "0.11.9"} stringcase = "^1.2.0" PySnooper = ">=0.4.1,<0.6.0" jinja2 = "^2.11.2" From 84d3a4477e56c57530819c34af2077acaf0ccb40 Mon Sep 17 00:00:00 2001 From: Koudai Aono Date: Mon, 2 Aug 2021 02:49:51 +0900 Subject: [PATCH 13/13] fix invalid data_type --- fastapi_code_generator/parser.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi_code_generator/parser.py b/fastapi_code_generator/parser.py index 2db2222..1886cf3 100644 --- a/fastapi_code_generator/parser.py +++ b/fastapi_code_generator/parser.py @@ -263,7 +263,7 @@ def get_parameter_type( if not data_type: if not schema: schema = parameters.schema_ - self.parse_schema(name, schema, [*path, name]) + data_type = self.parse_schema(name, schema, [*path, name]) if not schema: return None