From b3aee508828c5f0edb87cab2d7e52521b466bb4c Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 27 Mar 2023 19:06:54 +0300 Subject: [PATCH 01/20] partially functioning prototype. TODO: fix .model to ..model in imports.py visitor --- docs/__main.jinja2 | 22 ++ docs/__main.py | 230 +++++++++++++++++++++ docs/__parser.py | 455 ++++++++++++++++++++++++++++++++++++++++++ docs/__routers.jinja2 | 37 ++++ 4 files changed, 744 insertions(+) create mode 100644 docs/__main.jinja2 create mode 100644 docs/__main.py create mode 100644 docs/__parser.py create mode 100644 docs/__routers.jinja2 diff --git a/docs/__main.jinja2 b/docs/__main.jinja2 new file mode 100644 index 0000000..8d6a33d --- /dev/null +++ b/docs/__main.jinja2 @@ -0,0 +1,22 @@ +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import {{ routers | join(", ") }} + +app = FastAPI( + {% if info %} + {% for key,value in info.items() %} + {% set info_value= value.__repr__() %} + {{ key }} = {{info_value}}, + {% endfor %} + {% endif %} + ) + +{% for router in routers -%} +app.include_router({{router}}.router) +{% endfor -%} + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/docs/__main.py b/docs/__main.py new file mode 100644 index 0000000..8d7d308 --- /dev/null +++ b/docs/__main.py @@ -0,0 +1,230 @@ +from datetime import datetime, timezone +from importlib.util import module_from_spec, spec_from_file_location +from pathlib import Path +from typing import Any, Dict, List, Optional +import re +import typer +from datamodel_code_generator import LiteralType, PythonVersion, chdir +from datamodel_code_generator.format import CodeFormatter +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 OpenAPIParser +from fastapi_code_generator.visitor import Visitor + +app = typer.Typer() + +BUILTIN_TEMPLATE_DIR = Path(__file__).parent / "template" + +BUILTIN_VISITOR_DIR = Path(__file__).parent / "visitors" + +MODEL_PATH: Path = Path("models.py") + +TITLE_PATTERN = re.compile(r'(? Any: + module_name = module_path.stem + print("module_name:", module_name) + spec = spec_from_file_location(module_name, str(module_path)) + print("spec:", spec) + if spec: + module = module_from_spec(spec) + print("module:", module) + if spec.loader: + spec.loader.exec_module(module) + return module + raise Exception(f"{module_name} can not be loaded") + + +@app.command() +def main( + input_file: typer.FileText = typer.Option(..., "--input", "-i"), + output_dir: Path = typer.Option(..., "--output", "-o"), + model_file: str = typer.Option(None, "--model-file", "-m"), + template_dir: Optional[Path] = typer.Option(None, "--template-dir", "-t"), + enum_field_as_literal: Optional[LiteralType] = typer.Option( + None, "--enum-field-as-literal" + ), + use_router_api: Optional[str] = typer.Option( + None, "--use-router-api", "-R" + ), + custom_visitors: Optional[List[Path]] = typer.Option( + None, "--custom-visitor", "-c" + ), + disable_timestamp: bool = typer.Option(False, "--disable-timestamp"), +) -> None: + input_name: str = input_file.name + input_text: str = input_file.read() + if model_file: + model_path = Path(model_file).with_suffix('.py') + else: + model_path = MODEL_PATH + if use_router_api: + if enum_field_as_literal: + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + use_router_api, + enum_field_as_literal, + disable_timestamp=disable_timestamp, + ) + else: + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + use_router_api, + disable_timestamp=disable_timestamp, + ) + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + custom_visitors=custom_visitors, + disable_timestamp=disable_timestamp, + ) + + +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], + model_path: Optional[Path] = None, + use_router_api: Optional[str] = None, + enum_field_as_literal: Optional[str] = None, + custom_visitors: Optional[List[Path]] = [], + disable_timestamp: bool = False, +) -> None: + if not model_path: + model_path = MODEL_PATH + if not output_dir.exists(): + output_dir.mkdir(parents=True) + if not template_dir: + template_dir = BUILTIN_TEMPLATE_DIR + if use_router_api: + if enum_field_as_literal: + parser = OpenAPIParser(input_text, + enum_field_as_literal=enum_field_as_literal, + use_router_api=use_router_api) + else: + parser = OpenAPIParser(input_text, use_router_api=use_router_api) + else: + parser = OpenAPIParser(input_text) + 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( + template_dir if template_dir else f"{Path(__file__).parent}/template", + encoding="utf8", + ), + ) + + results: Dict[Path, str] = {} + code_formatter = CodeFormatter(PythonVersion.PY_38, Path().resolve()) + + template_vars: Dict[str, object] = {"info": parser.parse_info()} + visitors: List[Visitor] = [] + + # Load visitors + builtin_visitors = BUILTIN_VISITOR_DIR.rglob("*.py") + visitors_path = [*builtin_visitors, *(custom_visitors if custom_visitors else [])] + for visitor_path in visitors_path: + module = dynamic_load_module(visitor_path) + print("module_executed:", module) + module.__repr__() + if hasattr(module, "visit"): + visitors.append(module.visit) + else: + raise Exception(f"{visitor_path.stem} does not have any visit function") + + # Call visitors to build template_vars + for visitor in visitors: + visitor_result = visitor(parser, model_path) + template_vars = {**template_vars, **visitor_result} + # Convert from Tag Names to router_names + tags = use_router_api.split(",") + routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] + template_vars = {**template_vars, "routers": routers, "tags": tags} + + for target in template_dir.rglob("*.*"): + relative_path = target.relative_to(template_dir) + if relative_path == Path("routers/routers.jinja2"): + for router, tag in zip(routers, tags): + template_vars["tag"] = tag.strip() + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + router_path = Path("routers", router).with_suffix(".jinja2") + results[router_path] = code_formatter.format_code(result) + else: + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + results[relative_path] = code_formatter.format_code(result) + + timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat() + header = f"""\ +# generated by fastapi-codegen: +# filename: {Path(input_name).name}""" + if not disable_timestamp: + header += f"\n# timestamp: {timestamp}" + + for path, code in results.items(): + with output_dir.joinpath(path.with_suffix(".py")).open("wt") as file: + print(header, file=file) + print("", file=file) + print(code.rstrip(), file=file) + + header = f'''\ +# generated by fastapi-codegen: +# filename: {{filename}}''' + if not disable_timestamp: + header += f'\n# timestamp: {timestamp}' + + for path, body_and_filename in modules.items(): + body, filename = body_and_filename + if path is None: + file = None + else: + if not path.parent.exists(): + path.parent.mkdir(parents=True) + file = path.open('wt', encoding='utf8') + + print(header.format(filename=filename), file=file) + if body: + print('', file=file) + print(body.rstrip(), file=file) + + if file is not None: + file.close() + + +if __name__ == "__main__": + typer.run(main) diff --git a/docs/__parser.py b/docs/__parser.py new file mode 100644 index 0000000..96a7bac --- /dev/null +++ b/docs/__parser.py @@ -0,0 +1,455 @@ +from __future__ import annotations + +import pathlib +import re +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 ( + 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 +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, + ResponseObject, +) +from datamodel_code_generator.types import DataType, DataTypeManager, StrictTypes +from pydantic import BaseModel + +RE_APPLICATION_JSON_PATTERN: Pattern[str] = re.compile(r'^application/.*json$') + + +class CachedPropertyModel(BaseModel): + class Config: + arbitrary_types_allowed = True + keep_untouched = (cached_property,) + + +class Response(BaseModel): + status_code: str + description: Optional[str] + contents: Dict[str, JsonSchemaObject] + + +class Request(BaseModel): + description: Optional[str] + contents: Dict[str, JsonSchemaObject] + required: bool + + +class UsefulStr(str): + @classmethod + def __get_validators__(cls) -> Any: + yield cls.validate + + @classmethod + def validate(cls, v: Any) -> Any: + return cls(v) + + @property + def snakecase(self) -> str: + return stringcase.snakecase(self) + + @property + def pascalcase(self) -> str: + return stringcase.pascalcase(self) + + @property + def camelcase(self) -> str: + return stringcase.camelcase(self) + + +class Argument(CachedPropertyModel): + name: UsefulStr + type_hint: UsefulStr + default: Optional[UsefulStr] + default_value: Optional[UsefulStr] + required: bool + + def __str__(self) -> str: + return self.argument + + @cached_property + def argument(self) -> str: + if self.default is None and self.required: + return f'{self.name}: {self.type_hint}' + return f'{self.name}: {self.type_hint} = {self.default}' + + +class Operation(CachedPropertyModel): + method: UsefulStr + path: UsefulStr + operationId: Optional[UsefulStr] + description: Optional[str] + summary: Optional[str] + parameters: List[Dict[str, Any]] = [] + responses: Dict[UsefulStr, Any] = {} + deprecated: bool = False + imports: List[Import] = [] + security: Optional[List[Dict[str, List[str]]]] = None + tags: Optional[List[str]] + arguments: str = '' + snake_case_arguments: str = '' + request: Optional[Argument] = None + response: str = '' + additional_responses: Dict[str, Dict[str, str]] = {} + return_type: str = '' + + @cached_property + def type(self) -> UsefulStr: + """ + backwards compatibility + """ + return self.method + + @cached_property + def root_path(self) -> UsefulStr: + paths = self.path.split("/") + return UsefulStr(paths[1] if len(paths) > 1 else '') + + @cached_property + def snake_case_path(self) -> str: + return re.sub( + r"{([^\}]+)}", lambda m: stringcase.snakecase(m.group()), self.path + ) + + @cached_property + def function_name(self) -> str: + if self.operationId: + name: str = self.operationId + else: + path = re.sub(r'/{|/', '_', self.snake_case_path).replace('}', '') + name = f"{self.type}{path}" + return stringcase.snakecase(name) + + +@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, + use_router_api: Optional[List[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], + ) + self.operations: Dict[str, Operation] = {} + self._temporary_operation: Dict[str, Any] = {} + self.imports_for_fastapi: Imports = Imports() + self.data_types: List[DataType] = [] + self.use_router_api: use_router_api.split(",") + + def parse_info(self) -> Optional[Dict[str, Any]]: + result = self.raw_obj.get('info', {}).copy() + servers = self.raw_obj.get('servers') + if servers: + result['servers'] = servers + return result or None + + 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, + parameters: ParameterObject, + snake_case: bool, + path: List[str], + ) -> Optional[Argument]: + orig_name = parameters.name + if snake_case: + name = stringcase.snakecase(parameters.name) + else: + name = parameters.name + + schema: Optional[JsonSchemaObject] = None + 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_ + data_type = self.parse_schema(name, schema, [*path, name]) + if not schema: + return None + + field = DataModelField( + name=name, + data_type=data_type, + required=parameters.required or parameters.in_ == ParameterLocation.path, + ) + + if orig_name != name: + 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: + 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, + default=default, # type: ignore + default_value=schema.default, + required=field.required, + ) + + 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] = [] + + parameters = self._temporary_operation.get('_parameters') + if parameters: + for parameter in 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: + arguments.append(request) + + positional_argument: bool = False + for argument in arguments: + if positional_argument and argument.required and argument.default is None: + argument.default = UsefulStr('...') + positional_argument = argument.required + + return arguments + + 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') + ) + elif media_type == 'application/octet-stream': + arguments.append( + Argument( + name='file', # type: ignore + type_hint='UploadFile', # type: ignore + required=True, + ) + ) + self.imports_for_fastapi.append( + Import.from_full_path("fastapi.UploadFile") + ) + self._temporary_operation['_request'] = arguments[0] if arguments else None + + def parse_responses( + self, + 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) + else: + data_type = DataType(type='None') + type_hint = data_type.type_hint # TODO: change to lazy loading + self._temporary_operation['response'] = type_hint + return_types = {type_hint: data_type} + for status_code, additional_responses in data_types.items(): + if status_code != '200' and additional_responses: # 200 is processed above + data_type = list(additional_responses.values())[0] + if data_type: + self.data_types.append(data_type) + type_hint = data_type.type_hint # TODO: change to lazy loading + self._temporary_operation.setdefault('additional_responses', {})[ + status_code + ] = {'model': type_hint} + return_types[type_hint] = data_type + if len(return_types) == 1: + return_type = next(iter(return_types.values())) + else: + return_type = DataType(data_types=list(return_types.values())) + if return_type: + self.data_types.append(return_type) + self._temporary_operation['return_type'] = return_type.type_hint + return data_types + + def parse_operation( + self, + raw_operation: Dict[str, Any], + path: List[str], + ) -> None: + 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['arguments'] = self.get_arguments( + snake_case=False, path=path + ) + self._temporary_operation['snake_case_arguments'] = self.get_arguments( + snake_case=True, path=path + ) + + self.operations[resolved_path] = Operation( + **raw_operation, + **self._temporary_operation, + path=f'/{path_name}', # type: ignore + method=method, # type: ignore + ) diff --git a/docs/__routers.jinja2 b/docs/__routers.jinja2 new file mode 100644 index 0000000..aaec837 --- /dev/null +++ b/docs/__routers.jinja2 @@ -0,0 +1,37 @@ +from __future__ import annotations + +from fastapi import APIRouter +from fastapi import FastAPI + +{{imports}} + +router = APIRouter( + tags=['{{tag}}'] + ) + +{% for operation in operations %} +{% if operation.tags[0] == tag %} +@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} + {% if operation.additional_responses %} + , responses={ + {% for status_code, models in operation.additional_responses.items() %} + '{{ status_code }}': { + {% for key, model in models.items() %} + '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} + {% endfor %} + }{% if not loop.last %},{% endif %} + {% endfor %} + } + {% endif %} + {% if operation.tags%} + , tags={{operation.tags}} + {% endif %}) +def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: + {%- if operation.summary %} + """ + {{ operation.summary }} + """ + {%- endif %} + pass +{% endif %} +{% endfor %} \ No newline at end of file From 35cc3eb2f937744f7e33cd2c62d0b8048bf8826b Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Wed, 29 Mar 2023 12:56:27 +0300 Subject: [PATCH 02/20] functioning prototype --- fastapi_code_generator/__main__.py | 74 ++++++++++++++----- fastapi_code_generator/template/main.jinja2 | 32 ++------ .../template/routers.jinja2 | 37 ++++++++++ 3 files changed, 101 insertions(+), 42 deletions(-) create mode 100644 fastapi_code_generator/template/routers.jinja2 diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 25bb43e..11e6b09 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -2,7 +2,7 @@ from importlib.util import module_from_spec, spec_from_file_location from pathlib import Path from typing import Any, Dict, List, Optional - +import re import typer from datamodel_code_generator import LiteralType, PythonVersion, chdir from datamodel_code_generator.format import CodeFormatter @@ -22,12 +22,17 @@ MODEL_PATH: Path = Path("models.py") +TITLE_PATTERN = re.compile(r'(? Any: module_name = module_path.stem + print("module_name:", module_name) spec = spec_from_file_location(module_name, str(module_path)) + print("spec:", spec) if spec: module = module_from_spec(spec) + print("module:", module) if spec.loader: spec.loader.exec_module(module) return module @@ -43,6 +48,9 @@ def main( enum_field_as_literal: Optional[LiteralType] = typer.Option( None, "--enum-field-as-literal" ), + use_router_api: Optional[str] = typer.Option( + None, "--use-router-api", "-R" + ), custom_visitors: Optional[List[Path]] = typer.Option( None, "--custom-visitor", "-c" ), @@ -54,16 +62,28 @@ def main( model_path = Path(model_file).with_suffix('.py') else: model_path = MODEL_PATH - if enum_field_as_literal: - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - enum_field_as_literal, - disable_timestamp=disable_timestamp, - ) + if use_router_api: + if enum_field_as_literal: + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + use_router_api, + enum_field_as_literal, + disable_timestamp=disable_timestamp, + ) + else: + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + use_router_api, + disable_timestamp=disable_timestamp, + ) return generate_code( input_name, input_text, @@ -91,6 +111,7 @@ def generate_code( output_dir: Path, template_dir: Optional[Path], model_path: Optional[Path] = None, + use_router_api: Optional[str] = None, enum_field_as_literal: Optional[str] = None, custom_visitors: Optional[List[Path]] = [], disable_timestamp: bool = False, @@ -101,8 +122,13 @@ def generate_code( output_dir.mkdir(parents=True) if not template_dir: template_dir = BUILTIN_TEMPLATE_DIR - if enum_field_as_literal: - parser = OpenAPIParser(input_text, enum_field_as_literal=enum_field_as_literal) + if use_router_api: + if enum_field_as_literal: + parser = OpenAPIParser(input_text, + enum_field_as_literal=enum_field_as_literal, + use_router_api=use_router_api) + else: + parser = OpenAPIParser(input_text, use_router_api=use_router_api) else: parser = OpenAPIParser(input_text) with chdir(output_dir): @@ -133,6 +159,8 @@ def generate_code( visitors_path = [*builtin_visitors, *(custom_visitors if custom_visitors else [])] for visitor_path in visitors_path: module = dynamic_load_module(visitor_path) + print("module_executed:", module) + module.__repr__() if hasattr(module, "visit"): visitors.append(module.visit) else: @@ -142,12 +170,24 @@ def generate_code( for visitor in visitors: visitor_result = visitor(parser, model_path) template_vars = {**template_vars, **visitor_result} + # Convert from Tag Names to router_names + tags = use_router_api.split(",") + routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] + template_vars = {**template_vars, "routers": routers, "tags": tags} - for target in template_dir.rglob("*"): + for target in template_dir.rglob("routers.*"): relative_path = target.relative_to(template_dir) - template = environment.get_template(str(relative_path)) - result = template.render(template_vars) - results[relative_path] = code_formatter.format_code(result) + if relative_path == Path("routers.jinja2"): + for router, tag in zip(routers, tags): + template_vars["tag"] = tag.strip() + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + router_path = Path(router).with_suffix(".jinja2") + results[router_path] = code_formatter.format_code(result) + else: + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + results[relative_path] = code_formatter.format_code(result) timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat() header = f"""\ diff --git a/fastapi_code_generator/template/main.jinja2 b/fastapi_code_generator/template/main.jinja2 index 9e2df14..080b6aa 100644 --- a/fastapi_code_generator/template/main.jinja2 +++ b/fastapi_code_generator/template/main.jinja2 @@ -2,7 +2,7 @@ from __future__ import annotations from fastapi import FastAPI -{{imports}} +from . import {{ routers | join(", ") }} app = FastAPI( {% if info %} @@ -13,28 +13,10 @@ app = FastAPI( {% endif %} ) +{% for router in routers -%} +app.include_router({{router}}.router) +{% endfor -%} -{% for operation in operations %} -@app.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} - {% if operation.additional_responses %} - , responses={ - {% for status_code, models in operation.additional_responses.items() %} - '{{ status_code }}': { - {% for key, model in models.items() %} - '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} - {% endfor %} - }{% if not loop.last %},{% endif %} - {% endfor %} - } - {% endif %} - {% if operation.tags %} - , tags={{operation.tags}} - {% endif %}) -def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: - {%- if operation.summary %} - """ - {{ operation.summary }} - """ - {%- endif %} - pass -{% endfor %} +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/fastapi_code_generator/template/routers.jinja2 b/fastapi_code_generator/template/routers.jinja2 new file mode 100644 index 0000000..aaec837 --- /dev/null +++ b/fastapi_code_generator/template/routers.jinja2 @@ -0,0 +1,37 @@ +from __future__ import annotations + +from fastapi import APIRouter +from fastapi import FastAPI + +{{imports}} + +router = APIRouter( + tags=['{{tag}}'] + ) + +{% for operation in operations %} +{% if operation.tags[0] == tag %} +@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} + {% if operation.additional_responses %} + , responses={ + {% for status_code, models in operation.additional_responses.items() %} + '{{ status_code }}': { + {% for key, model in models.items() %} + '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} + {% endfor %} + }{% if not loop.last %},{% endif %} + {% endfor %} + } + {% endif %} + {% if operation.tags%} + , tags={{operation.tags}} + {% endif %}) +def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: + {%- if operation.summary %} + """ + {{ operation.summary }} + """ + {%- endif %} + pass +{% endif %} +{% endfor %} \ No newline at end of file From 6de5c131fde868073d40a45a9b329d3b052b43d7 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Wed, 29 Mar 2023 23:39:49 +0300 Subject: [PATCH 03/20] working version --- fastapi_code_generator/__main__.py | 110 ++++++++++-------- .../mytemplate/dependencies.jinja2 | 1 + fastapi_code_generator/mytemplate/main.jinja2 | 22 ++++ .../{template => mytemplate}/routers.jinja2 | 2 +- fastapi_code_generator/template/main.jinja2 | 32 +++-- 5 files changed, 110 insertions(+), 57 deletions(-) create mode 100644 fastapi_code_generator/mytemplate/dependencies.jinja2 create mode 100644 fastapi_code_generator/mytemplate/main.jinja2 rename fastapi_code_generator/{template => mytemplate}/routers.jinja2 (97%) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 11e6b09..cc02c1a 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -1,6 +1,6 @@ from datetime import datetime, timezone from importlib.util import module_from_spec, spec_from_file_location -from pathlib import Path +from pathlib import Path, PosixPath from typing import Any, Dict, List, Optional import re import typer @@ -16,23 +16,30 @@ app = typer.Typer() +custom_tags = None + +use_all_tags = False + +all_tags = [] + +TITLE_PATTERN = re.compile(r'(? Any: module_name = module_path.stem - print("module_name:", module_name) spec = spec_from_file_location(module_name, str(module_path)) - print("spec:", spec) if spec: module = module_from_spec(spec) - print("module:", module) if spec.loader: spec.loader.exec_module(module) return module @@ -48,8 +55,9 @@ def main( enum_field_as_literal: Optional[LiteralType] = typer.Option( None, "--enum-field-as-literal" ), - use_router_api: Optional[str] = typer.Option( - None, "--use-router-api", "-R" + use_router_api: bool = typer.Option(False, "--split-using-tags", "-s"), + custom_routers: Optional[str] = typer.Option( + None, "--exec-for-given-tags", "-g" ), custom_visitors: Optional[List[Path]] = typer.Option( None, "--custom-visitor", "-c" @@ -63,27 +71,24 @@ def main( else: model_path = MODEL_PATH if use_router_api: - if enum_field_as_literal: - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - use_router_api, - enum_field_as_literal, - disable_timestamp=disable_timestamp, - ) - else: - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - use_router_api, - disable_timestamp=disable_timestamp, - ) + global use_all_tags + use_all_tags = use_router_api + template_dir = MAIN_TEMPLATE_DIR + Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) + if custom_routers: + global custom_tags + custom_tags = custom_routers + + if enum_field_as_literal: + return generate_code( + input_name, + input_text, + output_dir, + template_dir, + model_path, + enum_field_as_literal, + disable_timestamp=disable_timestamp, + ) return generate_code( input_name, input_text, @@ -111,7 +116,6 @@ def generate_code( output_dir: Path, template_dir: Optional[Path], model_path: Optional[Path] = None, - use_router_api: Optional[str] = None, enum_field_as_literal: Optional[str] = None, custom_visitors: Optional[List[Path]] = [], disable_timestamp: bool = False, @@ -122,13 +126,8 @@ def generate_code( output_dir.mkdir(parents=True) if not template_dir: template_dir = BUILTIN_TEMPLATE_DIR - if use_router_api: - if enum_field_as_literal: - parser = OpenAPIParser(input_text, - enum_field_as_literal=enum_field_as_literal, - use_router_api=use_router_api) - else: - parser = OpenAPIParser(input_text, use_router_api=use_router_api) + if enum_field_as_literal: + parser = OpenAPIParser(input_text, enum_field_as_literal=enum_field_as_literal) else: parser = OpenAPIParser(input_text) with chdir(output_dir): @@ -159,8 +158,6 @@ def generate_code( visitors_path = [*builtin_visitors, *(custom_visitors if custom_visitors else [])] for visitor_path in visitors_path: module = dynamic_load_module(visitor_path) - print("module_executed:", module) - module.__repr__() if hasattr(module, "visit"): visitors.append(module.visit) else: @@ -170,24 +167,39 @@ def generate_code( for visitor in visitors: visitor_result = visitor(parser, model_path) template_vars = {**template_vars, **visitor_result} + + if use_all_tags: + for operation in template_vars.get("operations"): + if hasattr(operation, "tags"): + for tag in operation.tags: + all_tags.append(tag) # Convert from Tag Names to router_names - tags = use_router_api.split(",") - routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] - template_vars = {**template_vars, "routers": routers, "tags": tags} + routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in set(all_tags)] + template_vars = {**template_vars, "routers": routers, "tags": set(all_tags)} - for target in template_dir.rglob("routers.*"): + for target in template_dir.rglob("*"): relative_path = target.relative_to(template_dir) - if relative_path == Path("routers.jinja2"): + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + results[relative_path] = code_formatter.format_code(result) + + results.pop(PosixPath("routers.jinja2")) + if use_all_tags: + if custom_tags and Path(output_dir.joinpath("main.py")).exists(): + tags = set(str(custom_tags).split(",")) + routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] + template_vars["routers"] = routers + else: + tags = template_vars.get("tags") + + for target in ROUTER_TEMPLATE_DIR.rglob("routers.*"): + relative_path = target.relative_to(template_dir) for router, tag in zip(routers, tags): template_vars["tag"] = tag.strip() template = environment.get_template(str(relative_path)) result = template.render(template_vars) - router_path = Path(router).with_suffix(".jinja2") + router_path = Path("routers", router).with_suffix(".jinja2") results[router_path] = code_formatter.format_code(result) - else: - template = environment.get_template(str(relative_path)) - result = template.render(template_vars) - results[relative_path] = code_formatter.format_code(result) timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat() header = f"""\ diff --git a/fastapi_code_generator/mytemplate/dependencies.jinja2 b/fastapi_code_generator/mytemplate/dependencies.jinja2 new file mode 100644 index 0000000..ef3149f --- /dev/null +++ b/fastapi_code_generator/mytemplate/dependencies.jinja2 @@ -0,0 +1 @@ +{{imports}} \ No newline at end of file diff --git a/fastapi_code_generator/mytemplate/main.jinja2 b/fastapi_code_generator/mytemplate/main.jinja2 new file mode 100644 index 0000000..8d6a33d --- /dev/null +++ b/fastapi_code_generator/mytemplate/main.jinja2 @@ -0,0 +1,22 @@ +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import {{ routers | join(", ") }} + +app = FastAPI( + {% if info %} + {% for key,value in info.items() %} + {% set info_value= value.__repr__() %} + {{ key }} = {{info_value}}, + {% endfor %} + {% endif %} + ) + +{% for router in routers -%} +app.include_router({{router}}.router) +{% endfor -%} + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/fastapi_code_generator/template/routers.jinja2 b/fastapi_code_generator/mytemplate/routers.jinja2 similarity index 97% rename from fastapi_code_generator/template/routers.jinja2 rename to fastapi_code_generator/mytemplate/routers.jinja2 index aaec837..ad2eb40 100644 --- a/fastapi_code_generator/template/routers.jinja2 +++ b/fastapi_code_generator/mytemplate/routers.jinja2 @@ -3,7 +3,7 @@ from __future__ import annotations from fastapi import APIRouter from fastapi import FastAPI -{{imports}} +from ..dependencies import * router = APIRouter( tags=['{{tag}}'] diff --git a/fastapi_code_generator/template/main.jinja2 b/fastapi_code_generator/template/main.jinja2 index 080b6aa..9e2df14 100644 --- a/fastapi_code_generator/template/main.jinja2 +++ b/fastapi_code_generator/template/main.jinja2 @@ -2,7 +2,7 @@ from __future__ import annotations from fastapi import FastAPI -from . import {{ routers | join(", ") }} +{{imports}} app = FastAPI( {% if info %} @@ -13,10 +13,28 @@ app = FastAPI( {% endif %} ) -{% for router in routers -%} -app.include_router({{router}}.router) -{% endfor -%} -@app.get("/") -async def root(): - return {"message": "Gateway of the App"} +{% for operation in operations %} +@app.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} + {% if operation.additional_responses %} + , responses={ + {% for status_code, models in operation.additional_responses.items() %} + '{{ status_code }}': { + {% for key, model in models.items() %} + '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} + {% endfor %} + }{% if not loop.last %},{% endif %} + {% endfor %} + } + {% endif %} + {% if operation.tags %} + , tags={{operation.tags}} + {% endif %}) +def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: + {%- if operation.summary %} + """ + {{ operation.summary }} + """ + {%- endif %} + pass +{% endfor %} From 638a00ee0ca56c81999bdd79134d68d244f1b46e Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Wed, 29 Mar 2023 23:44:25 +0300 Subject: [PATCH 04/20] working version --- fastapi_code_generator/__main__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index cc02c1a..fd9c910 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -183,8 +183,8 @@ def generate_code( result = template.render(template_vars) results[relative_path] = code_formatter.format_code(result) - results.pop(PosixPath("routers.jinja2")) if use_all_tags: + results.pop(PosixPath("routers.jinja2")) if custom_tags and Path(output_dir.joinpath("main.py")).exists(): tags = set(str(custom_tags).split(",")) routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] From 26eddc597407303de9a58d0d5c899af759ad4d76 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 3 Apr 2023 21:19:51 +0300 Subject: [PATCH 05/20] working version --- README.md | 4 + fastapi_code_generator/__main__.py | 70 +- .../dependencies.jinja2 | 0 .../main.jinja2 | 0 .../routers.jinja2 | 0 tests/swagger.yaml | 3158 +++++++++++++++++ 6 files changed, 3197 insertions(+), 35 deletions(-) rename fastapi_code_generator/{mytemplate => modular_template}/dependencies.jinja2 (100%) rename fastapi_code_generator/{mytemplate => modular_template}/main.jinja2 (100%) rename fastapi_code_generator/{mytemplate => modular_template}/routers.jinja2 (100%) create mode 100644 tests/swagger.yaml diff --git a/README.md b/README.md index 0dd6635..e7752f2 100644 --- a/README.md +++ b/README.md @@ -354,3 +354,7 @@ visit: Visitor = custom_visitor fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license + + + +--input swagger.yaml --output app --split-using-tags --exec-for-given-tags "Instance Data Group, List Files" \ No newline at end of file diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index fd9c910..7ef60df 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -16,17 +16,11 @@ app = typer.Typer() -custom_tags = None - -use_all_tags = False - all_tags = [] TITLE_PATTERN = re.compile(r'(? None: if not model_path: model_path = MODEL_PATH @@ -168,14 +163,15 @@ def generate_code( visitor_result = visitor(parser, model_path) template_vars = {**template_vars, **visitor_result} - if use_all_tags: + if generate_routers: for operation in template_vars.get("operations"): if hasattr(operation, "tags"): for tag in operation.tags: all_tags.append(tag) # Convert from Tag Names to router_names - routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in set(all_tags)] - template_vars = {**template_vars, "routers": routers, "tags": set(all_tags)} + set_of_tags = set(all_tags) + routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in set_of_tags] + template_vars = {**template_vars, "routers": routers, "tags": set_of_tags} for target in template_dir.rglob("*"): relative_path = target.relative_to(template_dir) @@ -183,23 +179,27 @@ def generate_code( result = template.render(template_vars) results[relative_path] = code_formatter.format_code(result) - if use_all_tags: + if generate_routers: + tags = set_of_tags results.pop(PosixPath("routers.jinja2")) - if custom_tags and Path(output_dir.joinpath("main.py")).exists(): - tags = set(str(custom_tags).split(",")) - routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] - template_vars["routers"] = routers - else: - tags = template_vars.get("tags") - - for target in ROUTER_TEMPLATE_DIR.rglob("routers.*"): + if generate_routers_for_tags_filter: + if not Path(output_dir.joinpath("main.py")).exists(): + tags = set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(",")) + else: + with open(Path(output_dir.joinpath("main.py")), 'r') as file: + content = file.read() + if "app.include_router" in content: + tags = set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(",")) + + for target in BUILTIN_MODULAR_TEMPLATE_DIR.rglob("routers.*"): relative_path = target.relative_to(template_dir) - for router, tag in zip(routers, tags): - template_vars["tag"] = tag.strip() - template = environment.get_template(str(relative_path)) - result = template.render(template_vars) - router_path = Path("routers", router).with_suffix(".jinja2") - results[router_path] = code_formatter.format_code(result) + for router, tag in zip(routers, template_vars["tags"]): + if not Path(output_dir.joinpath("routers", router)).with_suffix(".py").exists() or tag in tags: + template_vars["tag"] = tag.strip() + template = environment.get_template(str(relative_path)) + result = template.render(template_vars) + router_path = Path("routers", router).with_suffix(".jinja2") + results[router_path] = code_formatter.format_code(result) timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat() header = f"""\ diff --git a/fastapi_code_generator/mytemplate/dependencies.jinja2 b/fastapi_code_generator/modular_template/dependencies.jinja2 similarity index 100% rename from fastapi_code_generator/mytemplate/dependencies.jinja2 rename to fastapi_code_generator/modular_template/dependencies.jinja2 diff --git a/fastapi_code_generator/mytemplate/main.jinja2 b/fastapi_code_generator/modular_template/main.jinja2 similarity index 100% rename from fastapi_code_generator/mytemplate/main.jinja2 rename to fastapi_code_generator/modular_template/main.jinja2 diff --git a/fastapi_code_generator/mytemplate/routers.jinja2 b/fastapi_code_generator/modular_template/routers.jinja2 similarity index 100% rename from fastapi_code_generator/mytemplate/routers.jinja2 rename to fastapi_code_generator/modular_template/routers.jinja2 diff --git a/tests/swagger.yaml b/tests/swagger.yaml new file mode 100644 index 0000000..9e07fb7 --- /dev/null +++ b/tests/swagger.yaml @@ -0,0 +1,3158 @@ +openapi: 3.0.0 +info: + version: 1.0.15 + title: OnBoarding Portal API + description: | + Here data owners can define and store configurations for new processes, + modify existing ones and submit final configurations for execution. + [here comes some link]( https://elbitsystems.com). +paths: + /projects: + get: + tags: + - Projects + summary: Get All Existing Projects For Processing. + description: Retrieve list of all projects and its attributes. + operationId: getAllProjects + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: is_enabled + in: query + required: false + schema: + type: boolean + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/Project" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "500": + description: Internal Server Error + post: + tags: + - Projects + summary: Create New Processing Project. + description: Create new project to use in processing. + operationId: createNewProject + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProjectPartial" + description: Project attributes and parameters. + required: true + responses: + "201": + description: Created + headers: + project_id: + description: Id of newly created project. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /projects/{project_id}: + get: + tags: + - Projects + summary: Get Existing Project For Processing. + description: Retrieve project and all its attributes by providing project id. + operationId: getProjectById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: project_id + in: path + required: true + description: The uuid of the processing project. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/Project" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Projects + summary: Update Project. + description: Updating existing project and its properties in DB. + operationId: updateProjectById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: project_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProjectUpdatable" + description: Modified project object and attributes to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + project_id: + description: Id of updated project. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /haveownfiles: + post: + tags: + - List Files + summary: Get Indication if prefix have own direct files. + description: Get Indication if prefix have own direct files. + operationId: getOwnFilesIndication + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/StorageListingRequest" + description: Parameters required for bucket keys retrieval. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: boolean + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /listfiles: + post: + tags: + - List Files + summary: Get List Of Files In Landing Zone. + description: Retrieve list of files subjected to use in processing. + operationId: getFileListByUrl + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/StorageListingRequest" + description: Parameters required for bucket keys retrieval. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + type: string + example: Texts/README.txt + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /listcommonprefixes: + post: + tags: + - List Files + summary: Get List Of Common Files Prefixes. + description: Retrieve list of common files prefixes. + operationId: getAllCommonFilePrefixes + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/StorageListingRequest" + description: List of prefixes. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + type: string + example: landingzone + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /fileinventory: + post: + tags: + - List Files + summary: Get Data/Metadata inventory grouped by extensions. + description: Get Data/Metadata inventory grouped by extensions. + operationId: getFileInventoryByUrl + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/FileInventoryRequest" + description: Parameters required for inventory grouped by extensions retrieval. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: '#/components/schemas/FileinventoryResponse' + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processors: + post: + tags: + - Processors + summary: Create Processor. + description: Create new processor. + operationId: createProcessor + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessorPartial" + description: Processor object that needed to be added to the DB. + required: true + responses: + "201": + description: Created + headers: + processor_id: + description: Id of newly created processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Processors + summary: Get All Processors. + description: Retrieve list of all processors. + operationId: getAllProcessors + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: processor_type + in: query + required: false + description: Type of the processor. + schema: + $ref: "#/components/schemas/ProcessorType" + - name: processor_status + in: query + required: false + description: Status of the processor. + schema: + $ref: "#/components/schemas/ProcessorStatus" + - name: processor_visibility + in: query + required: false + description: Visibility of the processor. + schema: + $ref: "#/components/schemas/ProcessorVisibility" + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/Processor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "500": + description: Internal Server Error + /processors/{processor_id}: + get: + tags: + - Processors + summary: Get Processor. + description: Retrieve processor by providing process id. + operationId: getProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: processor_id + in: path + required: true + description: The uuid of the processor. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/Processor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Processors + summary: Update Processor. + description: Updating existing processor in DB. + operationId: updateProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: processor_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessorUpdatable" + description: Modified processor object to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + processor_id: + description: Id of updated processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/used_processors: + post: + tags: + - Used Processors + summary: Create Used Processor. + description: Create new used processor. + operationId: createUsedProcessor + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsedProcessorPartial" + description: Used processor object that needed to be added to the DB. + required: true + responses: + "201": + description: Created + headers: + used_processor_id: + description: Id of newly created used processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Used Processors + summary: Get All Used Processors. + description: Retrieve list of all used processors. + operationId: getAllUsedProcessors + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/UsedProcessor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "500": + description: Internal Server Error + /processes/{process_id}/used_processors/{used_processor_id}: + get: + tags: + - Used Processors + summary: Get Used Processor. + description: Retrieve used processor by providing used processor id. + operationId: getUsedProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: used_processor_id + in: path + required: true + description: The uuid of used processor. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/UsedProcessor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Used Processors + summary: Update Used Processor. + description: Updating existing used processor in DB. + operationId: updateUsedProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: used_processor_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/UsedProcessorUpdatable" + description: Modified used processor object to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + used_processor_id: + description: Id of updated used processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /used_processors/{used_processor_id}/instances/{instance_id}/instance_used_processors: + post: + tags: + - Instance Used Processors + summary: Create Instance Used Processor. + description: Create new instance used processor. + operationId: createInstanceUsedProcessor + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: used_processor_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/InstanceUsedProcessorPartial" + description: Instance used processor object that needed to be added to the DB. + required: true + responses: + "201": + description: Created + headers: + used_processor_instance_id: + description: Id of newly created instance used processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Instance Used Processors + summary: Get All Instance Used Processors. + deprecated: true + description: Retrieve list of all instance used processors. + operationId: getAllInstancesUsedProcessors + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: used_processor_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/InstanceUsedProcessor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /used_processors/{used_processor_id}/instances/{instance_id}/instance_used_processors/{used_processor_instance_id}: + get: + tags: + - Instance Used Processors + summary: Get Instance Used Processor. + description: Retrieve instance used processor by providing used processor instance id. + operationId: getInstanceUsedProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: used_processor_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: used_processor_instance_id + in: path + required: true + description: The uuid of instance used processor. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/InstanceUsedProcessor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Instance Used Processors + summary: Update Instance Used Processor. + description: Updating existing instance used processor in DB. + operationId: updateInstanceUsedProcessorById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: used_processor_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: used_processor_instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/InstanceUsedProcessorPartial" + description: Modified instance used processor object to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + used_processor_instance_id: + description: Id of updated instance used processor. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes: + post: + tags: + - Process Blueprint + summary: Create Process Blueprint. + description: Create new process blueprint. + operationId: createProcessBlueprint + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessBlueprintPartial" + description: Process blueprint object that needed to be added to the DB. + required: true + responses: + "201": + description: Created + headers: + process_id: + description: Id of newly created process blueprint. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Process Blueprint + summary: Get All Process Blueprints. + description: Retrieve list of all process blueprints. + operationId: getAllProcessBlueprints + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: project_id + in: query + required: false + description: Project id + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessBlueprint" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "500": + description: Internal Server Error + /processes/{process_id}: + get: + tags: + - Process Blueprint + summary: Get Process Blueprint. + description: Retrieve blueprint process by providing process id. + operationId: getProcessBlueprintById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + description: The uuid of the process blueprint. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/ProcessBlueprint" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Process Blueprint + summary: Update Process Blueprint. + description: Updating existing process blueprint in DB. + operationId: updateProcessBlueprintById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessBlueprintUpdatable" + description: Modified process blueprint object to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + process_id: + description: Id of updated process. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "405": + description: Method Not Allowed + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/data_groups: + post: + tags: + - Process Data Group + summary: Add Data Group To Process Blueprint. + description: Creates and adds new data group to existing blueprint of the process by + providing process id. + operationId: createProcessDataGroups + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" + description: Data groups of process blueprint that needed to be added to the DB. + required: true + responses: + "201": + description: Created + headers: + data_group_id: + description: Id of newly created data group. + schema: + type: string + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Process Data Group + summary: Get All Data Groups Of Process Blueprint. + description: Retrieve all data groups of existing process blueprint. + operationId: getAllProcessDataGroups + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: data_group_type + in: query + required: false + schema: + $ref: "#/components/schemas/DataGroupType" + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessBlueprintDataGroup" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/data_groups/{data_group_id}: + get: + tags: + - Process Data Group + summary: Get Data Group Of Process Blueprint. + description: Retrieve data group of existing process blueprint by providing process + id and data group id. + operationId: getProcessDataGroupById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: data_group_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/ProcessBlueprintDataGroup" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Process Data Group + summary: Update Data Group Of Process Blueprint. + description: Updating data group of existing process blueprint in DB. + operationId: updateDataGroupById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: data_group_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" + description: Modified data group object to update in DB. + required: true + responses: + "200": + description: Successful response. + headers: + data_group_id: + description: Id of updated process data group. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "405": + description: Method Not Allowed + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances: + post: + tags: + - Process Instance + summary: Create Process Instance. + description: Create new process instance. + operationId: createProcessInstance + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessInstancePartial" + description: Process instance object that needed to be added to DB. + required: true + responses: + "201": + description: Created + headers: + instance_id: + description: Id of newly created process instance. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Process Instance + summary: Get All Process Instances. + description: Retrieve list of all process instances. + operationId: getAllProcessInstances + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessInstance" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances/{instance_id}: + get: + tags: + - Process Instance + summary: Get Process Instance. + description: Retrieve instance of a process by providing process id and instance id. + operationId: getProcessInstanceById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + description: The uuid of the process blueprint. + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + description: The uuid of instance of a process. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/ProcessInstance" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Process Instance + summary: Update Process Instance. + description: Updating existing process instance in DB. + operationId: updateProcessInstanceById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessInstanceUpdatable" + description: Modified process instance object and data groups to update the DB. + required: true + responses: + "200": + description: Successful response. + headers: + instance_id: + description: Id of updated instance. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "405": + description: Method Not Allowed + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances/{instance_id}/instance_used_processors: + get: + tags: + - Instance Used Processors + summary: Get All Instance Used Processors + description: | + Get all instance used processor by providing instance id and process id. + operationId: getAllInstanceUsedProcessors + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/InstanceUsedProcessor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances/{instance_id}/runs: + get: + tags: + - Process Instance + summary: Get Runs Of Process Instances. + description: | + Get runs of process instance ordered by date submitted on + in descending order. + operationId: getInstanceRunsSortedBySubmittedOn + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: run_type + in: query + required: false + schema: + $ref: "#/components/schemas/RunType" + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessInstanceRun" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /process_instance_runs: + get: + tags: + - Process Instance + summary: Get Runs Of Process Instances By Params. + description: | + Get runs of process instance created between requested dates. + operationId: getInstanceRunsByRequestedParams + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: from_created_date + in: query + required: false + schema: + type: string + format: date-time + - name: to_created_date + in: query + required: false + schema: + type: string + format: date-time + - name: project_id + in: query + required: false + schema: + type: string + format: uuid + - name: process_id + in: query + required: false + schema: + type: string + format: uuid + - name: instance_id + in: query + required: false + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessInstanceRunSelected" + "400": + description: Bad Request + "403": + description: Forbidden + "422": + description: Validation Error + "500": + description: Internal Server Error + /data_group/{data_group_id}/instances/{instance_id}/instance_data_groups: + post: + tags: + - Instance Data Group + summary: Create Instance Data Group Of Process Instance. + description: Create new instance data group and add it to existing process instance. + operationId: createInstanceDataGroup + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: data_group_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" + description: Instance data group object that needed to be added to DB. + required: true + responses: + "201": + description: Created + headers: + data_group_instance_id: + description: Id of newly created instance data group. + schema: + type: string + "400": + description: Bad Request + "403": + description: Forbidden + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + get: + tags: + - Instance Data Group + summary: Get All Instance Data Groups Of Process Instance. + deprecated: true + description: Retrieve instance data group of existing process instance by + providing data group id and instance id. + operationId: getInstanceDataGroup + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: data_group_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessInstanceDataGroup" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /data_group/{data_group_id}/instances/{instance_id}/instance_data_groups/{data_group_instance_id}: + get: + tags: + - Instance Data Group + summary: Get Instance Data Group Of Process Instance. + description: Retrieve instance data group of existing process instance by providing + data group id, instance id and requested instance data group id. + operationId: getInstanceDataGroupById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: data_group_id + in: path + required: true + description: The uuid of data group. + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + description: The uuid of process instance. + schema: + type: string + format: uuid + - name: data_group_instance_id + in: path + required: true + description: The uuid of instance data group. + schema: + type: string + format: uuid + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/ProcessInstanceDataGroup" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + put: + tags: + - Instance Data Group + summary: Update Instance Data Group Of Process Instance. + description: Update instance data group of existing process instance by providing + data group id, instance id and instance data group id. + operationId: updateInstanceDataGroupById + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: data_group_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: data_group_instance_id + in: path + required: true + schema: + type: string + format: uuid + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" + description: Modified instance data group of existing process instance. + required: true + responses: + "200": + description: Successful response. + headers: + data_group_instance_id: + description: Id of updated instance data group. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "405": + description: Method Not Allowed + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances/{instance_id}/submit/{run_type}: + get: + tags: + - Process Instance + summary: Verify Eligibility Of Instance For Submitting. + description: Verify if instance eligible to be submitted for run of specific type. + operationId: isProcessInstanceSubmittable + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: run_type + in: path + required: true + schema: + $ref: "#/components/schemas/RunType" + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: boolean + + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + post: + tags: + - Process Instance + summary: Submit Execution Request For Finalized Process Instance. + description: Submitting predefined process instance along with all associated + instance data groups to the server for further execution. + operationId: submitProcessInstance + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: run_type + in: path + required: true + schema: + $ref: "#/components/schemas/RunType" + responses: + "202": + description: Accepted + headers: + run_id: + description: Id of submitted run. + schema: + type: string + format: uuid + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "405": + description: Method Not Allowed + "409": + description: Database Conflict + "422": + description: Validation Error + "500": + description: Internal Server Error + /processes/{process_id}/instances/{instance_id}/instance_data_groups: + get: + tags: + - Instance Data Group + summary: Get All Instance Data Groups Of Process Instance. + description: Retrieve all instance data groups of existing process instance by + providing data group id, instance id and requested data group type. + operationId: getAllInstanceDataGroups + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + - name: process_id + in: path + required: true + schema: + type: string + format: uuid + - name: instance_id + in: path + required: true + schema: + type: string + format: uuid + - name: data_group_type + in: query + required: false + description: Type of data group. + schema: + $ref: "#/components/schemas/DataGroupType" + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/ProcessInstanceDataGroup" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processing_chain/next_chainable_processors: + post: + tags: + - Process Blueprint Processing Chain + summary: Get All Next Chainable Processors. + description: Retrieve all next chainable processors by providing process id. + operationId: getNextChainableProcessors + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/NextChainableProcessorRequest" + description: Parameters required for retrieving next chainable processors. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + type: array + items: + $ref: "#/components/schemas/Processor" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processing_chain/next_chainable_datagroup: + post: + tags: + - Process Blueprint Processing Chain + summary: Get Next Chainable Data Group. + description: Retrieve next chainable data group by providing process id. + operationId: getNextChainableDatagroup + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/NextChainableDatagroupRequest" + description: Parameters required for retrieving next chainable datagroup. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/NextChainableDatagroupResponse" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error + /processing_chain/next_chainable_instance_datagroup: + post: + tags: + - Process Instance Processing Chain + summary: Get Next Chainable Data Group. + description: Retrieve next chainable data group by providing process id. + operationId: getNextChainableInstanceDatagroup + parameters: + - name: X-User + in: header + required: true + schema: + type: string + - name: X-User-Groups + in: header + required: true + schema: + type: string + requestBody: + content: + application/json: + schema: + $ref: "#/components/schemas/NextChainableInstanceDatagroupRequest" + description: Parameters required for retrieving next chainable datagroup. + responses: + "200": + description: Successful response. + content: + "*/*": + schema: + $ref: "#/components/schemas/NextChainableInstanceDatagroupResponse" + "400": + description: Bad Request + "403": + description: Forbidden + "404": + description: Not Found + "422": + description: Validation Error + "500": + description: Internal Server Error +servers: + - url: / + - url: /secure/api/v1/onboardingportalapi + - url: http://localhost:8080/ + - url: http://onboardingportalapi:8080/ + - url: http://onboardingportalapi.daita.devbit.io:8081/ + +components: + schemas: + FileinventoryResponse: + type: object + properties: + common_md: + type: boolean + description: indication for common.md.json file occurrence in directory + example: false + partial_md: + type: boolean + description: indication for partial.md.json file occurrence in directory + example: false + extensions: + type: array + description: list of extensions and quantities of files aggregations by extension + items: + type: object + properties: + ext: + type: string + description: extension of data files + example: "mpeg" + data_count: + type: integer + description: quantity of data files in directory aggregated by extension + example: 39 + md_count: + type: integer + description: quantity of metadata files in directory aggregated by extension + example: 39 + common_ext_md: + type: boolean + description: indication for common_{ext}.md.json file occurrence in directory + example: false + partial_ext_md: + type: boolean + description: indication for partial_{ext}.md.json file occurrence in directory + example: true + required: + - ext + - data_count + - md_count + - common_ext_md + - partial_ext_md + collisions_count: + type: integer + description: quantity of collisions by filename in destination bucket directory + example: 1 + collisions_samples: + type: array + description: samples of filenames having collision in destination bucket directory + items: + type: string + description: filename + example: "test_flight_001.mpeg" + required: + - common_md + - partial_md + - extensions + - collisions_count + - collisions_samples + + NextChainableDatagroupRequest: + type: object + properties: + processor_id: + type: string + format: uuid + example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d + input_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + suppl_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + required: + - processor_id + - input_datagroup_manifest + - suppl_datagroup_manifest + NextChainableDatagroupResponse: + type: object + properties: + output_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + reduce_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + required: + - output_datagroup_manifest + - reduce_datagroup_manifest + NextChainableInstanceDatagroupRequest: + type: object + properties: + processor_id: + type: string + format: uuid + example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d + input_datagroup: + $ref: "#/components/schemas/InstanceDataGroupValues" + suppl_datagroup: + $ref: "#/components/schemas/InstanceDataGroupValues" + required: + - processor_id + - input_datagroup + - suppl_datagroup + NextChainableInstanceDatagroupResponse: + type: object + properties: + output_datagroup: + $ref: "#/components/schemas/InstanceDataGroupValues" + reduce_datagroup: + $ref: "#/components/schemas/InstanceDataGroupValues" + required: + - output_datagroup + - reduce_datagroup + NextChainableProcessorRequest: + type: object + properties: + input_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + suppl_datagroup_manifest: + $ref: "#/components/schemas/ExtractManifest" + required: + - input_datagroup_manifest + - suppl_datagroup_manifest + RunType: + type: string + enum: + - validation + - processing + - ingestion + example: validation + ProcessorType: + type: string + enum: + - validator + - extractor + - ingestor + - processor + - reshape + example: extractor + ProcessorStatus: + type: string + enum: + - draft + - testrun + - enabled + - obsolete + - disabled + example: enabled + ProcessorVisibility: + type: string + enum: + - system + - private + - project + - groups + - public + example: public + DataGroupType: + type: string + enum: + - initial + - existing + - intermediate + - final + example: initial + FileInventoryRequest: + allOf: + - $ref: "#/components/schemas/StorageListingRequest" + - properties: + raw_zone_bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: test-raw-zone + description: Base URL of the bucket. + required: + - raw_zone_bucket + + StorageListingRequest: + type: object + properties: + access_key: + type: string + pattern: ^[A-Z0-9]{20}$ + example: ABCDEFGHIJKLMNOPQRST + description: Secret access key provided by client for authentication + purposes. + secret_access_key: + type: string + pattern: ^[a-zA-Z0-9/\+]{40}$ + example: 6GLuEBb8e35ceyH6GLuEBb8e35ceyH/+6GLuEBb8 + description: Secret access key provided by client for authentication + purposes. + region_name: + type: string + example: eu-west-1 + description: AWS Region. + endpoint_override_url: + type: string + format: uri + example: http://minio:9000 + description: Overridden storage URL + bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: test-landing-zone + description: Base URL of the bucket. + prefix: + type: string + example: objectstorage + description: Prefix of the keys block. + required: + - access_key + - secret_access_key + - bucket + Processor: + allOf: + - properties: + processor_id: + type: string + format: uuid + example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d + - $ref: "#/components/schemas/ProcessorPartial" + - $ref: "#/components/schemas/ChangeTrackingBlock" + required: + - processor_id + ProcessorPartial: + allOf: + - properties: + project_id: + type: string + format: uuid + example: dca74c6d-91cc-4c6d-a791-a7f7bc291ccd + - $ref: "#/components/schemas/ProcessorUpdatable" + required: + - project_id + ProcessorUpdatable: + allOf: + - properties: + parent_processor_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-a7f7bc2391dd + processor_name: + type: string + example: Extract Header + processor_version: + type: string + example: 2.3.2.1 + multiplicity: + type: string + enum: + - single + - multiple + example: multiple + description: + type: string + example: Extracting column names from header of the file. + processor_type: + $ref: "#/components/schemas/ProcessorType" + encapsulation: + type: string + enum: + - docker + - wheel + - maven + example: wheel + artifact_ref: + type: string + example: land/video_metadata:1.3.0.2 + entrypoint: + type: string + example: SomeTimesIsNotExitOne + processor_status: + $ref: "#/components/schemas/ProcessorStatus" + processor_visibility: + $ref: "#/components/schemas/ProcessorVisibility" + processor_manifest: + $ref: "#/components/schemas/ProcessorManifest" + default_env_parameters: + type: object + description: Unbound empty object describing default environmental parameters.TBD.FFU. + default_program_arguments: + type: object + description: Unbound empty object describing default program arguments.TBD.FFU. + + required: + - processor_name + - processor_version + - multiplicity + - processor_type + - encapsulation + - artifact_ref + - processor_status + - processor_visibility + - default_env_parameters + - default_program_arguments + + UsedProcessor: + allOf: + - properties: + used_processor_id: + type: string + format: uuid + example: d391ddf6-91cc-4c6d-a7f7-91cc91cc91cc + process_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-91cc91cc91cc + - $ref: "#/components/schemas/UsedProcessorPartial" + required: + - used_processor_id + - process_id + UsedProcessorPartial: + allOf: + - properties: + processor_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-91cc91cc91cc + - $ref: "#/components/schemas/UsedProcessorUpdatable" + required: + - processor_id + UsedProcessorUpdatable: + properties: + override_env_parameters: + type: object + description: Unbound empty object describing overridden environmental + parameters.TBD.FFU. + override_program_arguments: + type: object + description: Unbound empty object describing overridden program arguments.TBD.FFU. + required: + - override_env_parameters + - override_program_arguments + InstanceUsedProcessor: + allOf: + - properties: + used_processor_instance_id: + type: string + format: uuid + example: d391ddf6-91cc-4c6d-a7f7-91cc9191cccc + instance_id: + type: string + format: uuid + example: a7f7b5f6-91cc-b5f6-a7f7-91cc91cc91cc + used_processor_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-a7f7bc2391dd + - $ref: "#/components/schemas/InstanceUsedProcessorPartial" + required: + - used_processor_instance_id + - used_processor_id + - instance_id + InstanceUsedProcessorPartial: + properties: + override_program_arguments: + type: object + description: Unbound empty object describing overridden program arguments.TBD.FFU. + override_env_parameters: + type: object + description: Unbound empty object describing overridden environmental + parameters.TBD.FFU. + required: + - override_program_arguments + - override_env_parameters + ProcessBlueprint: + allOf: + - properties: + process_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-2989bc2342bb + parent_process_id: + type: string + format: uuid + example: 5adda535-6360-461e-a245-5c74b2eaac11 + - $ref: "#/components/schemas/ProcessBlueprintPartial" + - $ref: "#/components/schemas/ChangeTrackingBlock" + required: + - process_id + ProcessBlueprintPartial: + allOf: + - properties: + project_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-2989bc235c74 + - $ref: "#/components/schemas/ProcessBlueprintUpdatable" + required: + - project_id + ProcessBlueprintUpdatable: + allOf: + - properties: + process_name: + type: string + example: CopyFiles + process_version: + type: string + example: 1.0.0.0 + description: + type: string + example: Here comes some text to describe the process blueprint. + process_status: + type: string + enum: + - draft + - testrun + - enabled + - obsolete + - disabled + example: enabled + process_visibility: + type: string + enum: + - private + - project + - groups + - public + example: public + data_processor_dag: + $ref: "#/components/schemas/DataProcessorDAG" + + required: + - process_name + - process_version + - data_processor_dag + + ProcessInstance: + allOf: + - properties: + instance_id: + type: string + format: uuid + example: 70bdcbc7-3dbb-47da-a425-dfc110410892 + process_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-2989bc2342bb + - $ref: "#/components/schemas/ProcessInstancePartial" + - $ref: "#/components/schemas/ChangeTrackingBlock" + required: + - instance_id + - process_id + ProcessInstanceUpdatable: + allOf: + - properties: + description: + type: string + example: Here comes some text to describe the process instance. + - $ref: "#/components/schemas/InitialMetadata" + ProcessInstancePartial: + allOf: + - properties: + project_storage_spec: + type: string + format: uuid + example: 70bdcbc7-3dbb-47da-a425-dfc110dfc112 + - $ref: "#/components/schemas/ProcessInstanceUpdatable" + required: + - project_storage_spec + InitialMetadata: + properties: + initial_metadata: + type: object + description: Unbound empty object describing initial metadata.TBD.FFU. + required: + - initial_metadata + ChangeTrackingBlock: + properties: + created_by: + type: string + example: UserA + created_on: + type: string + format: date-time + example: 2022-03-05T14:20:00.245Z + last_modified_by: + type: string + example: UserA + last_modified_on: + type: string + format: date-time + example: 2022-03-05T14:20:00.245Z + required: + - created_by + - created_on + ProcessBlueprintDataGroup: + allOf: + - properties: + data_group_id: + type: string + format: uuid + example: 85b285e0-8bed-4271-aaef-a4a09aa56fae + process_id: + type: string + format: uuid + example: a4a09ae0-8bed-aaef-aaef-a4a0aaefaaef + - $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" + required: + - data_group_id + ProcessBlueprintDataGroupPartial: + type: object + properties: + group_name: + type: string + example: vis_thermal_8bit_triplets/vis/bmp + metadata_extractor: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa28bba + data_group_type: + $ref: "#/components/schemas/DataGroupType" + data_group_manifest: + $ref: "#/components/schemas/ExtractManifest" + description: + type: string + example: Here comes some text to describe the data group. + required: + - group_name + - data_group_type + - data_group_manifest + ProcessInstanceDataGroup: + type: object + allOf: + - properties: + data_group_instance_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa28bed + data_group_id: + type: string + format: uuid + example: 7f7285e0-8bed-8bed-aaef-a4a09aa2aaef + instance_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa28bba + data_is_ingested: + type: boolean + example: false + metadata_schema_is_valid: + type: boolean + example: false + validated_data_file_count: + type: integer + example: 1 + ingested_data_file_count: + type: integer + example: 2 + - $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" + required: + - data_group_instance_id + - data_group_id + - instance_id + ProcessInstanceDataGroupPartial: + type: object + properties: + data_file_count: + type: integer + example: 3 + metadata_file_count: + type: integer + example: 2 + data_group_values: + $ref: "#/components/schemas/InstanceDataGroupValues" + required: + - data_group_values + ProcessInstanceRun: + type: object + properties: + run_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa23e1a + instance_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45ead + run_type: + $ref: "#/components/schemas/RunType" + dag_run_id: + type: string + example: DR-0003 + submitted_on: + type: string + format: date-time + example: 2022-03-06T09:48:13.236Z + submitted_by: + type: string + example: UserA + started_on: + type: string + format: date-time + example: 2022-03-07T09:52:01.187Z + failed_on: + type: string + format: date-time + example: 2022-03-07T10:15:00.201Z + finished_on: + type: string + format: date-time + example: 2022-03-07T10:15:00.201Z + required: + - run_id + - instance_id + - submitted_by + - submitted_on + - run_type + ProcessInstanceRunSelected: + type: object + properties: + process_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa23e1a + instance_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45ead + project_id: + type: string + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc + process_name: + type: string + example: Convert files + process_version: + type: string + example: 1.4.1.7 + created_on: + type: string + format: date-time + example: 2022-03-06T09:48:13.236Z + created_by: + type: string + example: UserA + validation_last_run_id: + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc + validation_last_run_status: + type: string + example: Finished + ingestion_last_run_id: + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc + ingestion_last_run_status: + type: string + example: Failed + processing_last_run_id: + format: uuid + example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc + processing_last_run_status: + type: string + example: Finished + is_processing_dag: + type: boolean + example: true + is_initial_datagroups: + type: boolean + example: false + total_data_file_count: + type: integer + example: 3 + total_validated_data_file_count: + type: integer + example: 2 + total_ingested_data_file_count: + type: integer + example: 1 + + required: + - process_id + - instance_id + - process_name + - process_version + - created_on + - created_by + - is_processing_dag + - is_initial_datagroups + + Project: + allOf: + - properties: + project_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-2989bc2332ea + project_storage_spec_id: + type: string + format: uuid + example: dca7b5f6-91cc-4c6d-a7f7-2989bc1745de + valid_from: + type: string + format: date-time + example: 2022-05-07T12:13:00.201Z + valid_until: + type: string + format: date-time + example: 2022-05-13T17:19:00.201Z + - $ref: "#/components/schemas/ProjectPartial" + - $ref: "#/components/schemas/ChangeTrackingBlock" + required: + - project_id + - valid_from + - valid_until + ProjectPartial: + allOf: + - properties: + project_ref_id: + type: string + example: n312 + - $ref: "#/components/schemas/ProjectUpdatable" + required: + - project_ref_id + ProjectUpdatable: + allOf: + - properties: + project_name: + type: string + example: Moving Vehicles + description: + type: string + example: Description of the project. + is_enabled: + type: boolean + example: true + ldap_groups: + type: array + items: + type: string + example: administrators + landing_zone_bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: no2227764-landing-zone + raw_zone_bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: no2227764-raw-zone + processed_zone_bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: no2227764-processed-zone + archive_zone_bucket: + type: string + pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ + example: no2227764-archive-zone + endpoint_override_url: + type: string + format: uri + example: http://minio:9000 + region_name: + type: string + example: us-east-1 + account_id: + type: string + example: "123456789" + account_user: + type: string + example: minioadmin + account_password: + type: string + example: minioadmin + storage_type: + $ref: "#/components/schemas/StorageType" + required: + - project_name + - is_enabled + - landing_zone_bucket + - raw_zone_bucket + - processed_zone_bucket + - archive_zone_bucket + - account_user + - account_password + ProcessorManifest: + type: object + properties: + inputManifest: + $ref: "#/components/schemas/ExtractManifest" + supplManifest: + $ref: "#/components/schemas/ExtractManifest" + outputManifest: + $ref: "#/components/schemas/ReplaceManifest" + reduceManifest: + $ref: "#/components/schemas/ReplaceManifest" + inputMetadata: + $ref: "#/components/schemas/FlagManifest" + inputUpdateMetadata: + $ref: "#/components/schemas/FlagManifest" + supplMetadata: + $ref: "#/components/schemas/FlagManifest" + outputMetadata: + $ref: "#/components/schemas/FlagManifest" + reduceMetadata: + $ref: "#/components/schemas/FlagManifest" + inputLineage: + $ref: "#/components/schemas/FlagManifest" + supplLineage: + $ref: "#/components/schemas/FlagManifest" + outputLineage: + $ref: "#/components/schemas/FlagManifest" + reduceLineage: + $ref: "#/components/schemas/FlagManifest" + additionalProperties: false + required: + - inputManifest + - supplManifest + - outputManifest + - reduceManifest + - inputMetadata + - inputUpdateMetadata + - supplMetadata + - outputMetadata + - reduceMetadata + - inputLineage + - supplLineage + - outputLineage + - reduceLineage + ExtractManifest: + type: array + items: + type: string + example: camera/(.*).mp4 + description: Regular expression with capturing groups to match extract filename elements + ReplaceManifest: + type: array + items: + type: string + example: camera/#1$1.mp3 + description: | + Expression with tuple index and capturing group to replace + filename with extracted elements + FlagManifest: + type: array + items: + type: boolean + example: true + DataProcessorDAG: + type: array + items: + oneOf: + - $ref: "#/components/schemas/InputLink" + - $ref: "#/components/schemas/OutputLink" + - $ref: "#/components/schemas/ControlLink" + InputLink: + type: object + properties: + inputDataGroups: + type: array + items: + type: string + format: uuid + supplDataGroups: + type: array + items: + type: string + format: uuid + usedProcessor: + type: string + format: uuid + additionalProperties: false + required: + - inputDataGroups + - supplDataGroups + - usedProcessor + OutputLink: + type: object + properties: + usedProcessor: + type: string + format: uuid + outputDataGroups: + type: array + items: + type: string + format: uuid + reduceDataGroups: + type: array + items: + type: string + format: uuid + additionalProperties: false + required: + - usedProcessor + - outputDataGroups + - reduceDataGroups + ControlLink: + type: object + properties: + fromUsedProcessor: + type: string + format: uuid + toUsedProcessor: + type: string + format: uuid + additionalProperties: false + required: + - fromUsedProcessor + - toUsedProcessor + StorageType: + type: string + enum: + - netapp + - minio + - aws + example: minio + InstanceDataGroupValues: + type: array + items: + type: array + items: + type: string + example: camera/*image*.MP4 \ No newline at end of file From 98eea6277d8408382e897b25995faf348e55d929 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 3 Apr 2023 21:20:31 +0300 Subject: [PATCH 06/20] working version --- docs/__main.jinja2 | 22 -- docs/__main.py | 230 --------------------- docs/__parser.py | 455 ------------------------------------------ docs/__routers.jinja2 | 37 ---- 4 files changed, 744 deletions(-) delete mode 100644 docs/__main.jinja2 delete mode 100644 docs/__main.py delete mode 100644 docs/__parser.py delete mode 100644 docs/__routers.jinja2 diff --git a/docs/__main.jinja2 b/docs/__main.jinja2 deleted file mode 100644 index 8d6a33d..0000000 --- a/docs/__main.jinja2 +++ /dev/null @@ -1,22 +0,0 @@ -from __future__ import annotations - -from fastapi import FastAPI - -from .routers import {{ routers | join(", ") }} - -app = FastAPI( - {% if info %} - {% for key,value in info.items() %} - {% set info_value= value.__repr__() %} - {{ key }} = {{info_value}}, - {% endfor %} - {% endif %} - ) - -{% for router in routers -%} -app.include_router({{router}}.router) -{% endfor -%} - -@app.get("/") -async def root(): - return {"message": "Gateway of the App"} diff --git a/docs/__main.py b/docs/__main.py deleted file mode 100644 index 8d7d308..0000000 --- a/docs/__main.py +++ /dev/null @@ -1,230 +0,0 @@ -from datetime import datetime, timezone -from importlib.util import module_from_spec, spec_from_file_location -from pathlib import Path -from typing import Any, Dict, List, Optional -import re -import typer -from datamodel_code_generator import LiteralType, PythonVersion, chdir -from datamodel_code_generator.format import CodeFormatter -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 OpenAPIParser -from fastapi_code_generator.visitor import Visitor - -app = typer.Typer() - -BUILTIN_TEMPLATE_DIR = Path(__file__).parent / "template" - -BUILTIN_VISITOR_DIR = Path(__file__).parent / "visitors" - -MODEL_PATH: Path = Path("models.py") - -TITLE_PATTERN = re.compile(r'(? Any: - module_name = module_path.stem - print("module_name:", module_name) - spec = spec_from_file_location(module_name, str(module_path)) - print("spec:", spec) - if spec: - module = module_from_spec(spec) - print("module:", module) - if spec.loader: - spec.loader.exec_module(module) - return module - raise Exception(f"{module_name} can not be loaded") - - -@app.command() -def main( - input_file: typer.FileText = typer.Option(..., "--input", "-i"), - output_dir: Path = typer.Option(..., "--output", "-o"), - model_file: str = typer.Option(None, "--model-file", "-m"), - template_dir: Optional[Path] = typer.Option(None, "--template-dir", "-t"), - enum_field_as_literal: Optional[LiteralType] = typer.Option( - None, "--enum-field-as-literal" - ), - use_router_api: Optional[str] = typer.Option( - None, "--use-router-api", "-R" - ), - custom_visitors: Optional[List[Path]] = typer.Option( - None, "--custom-visitor", "-c" - ), - disable_timestamp: bool = typer.Option(False, "--disable-timestamp"), -) -> None: - input_name: str = input_file.name - input_text: str = input_file.read() - if model_file: - model_path = Path(model_file).with_suffix('.py') - else: - model_path = MODEL_PATH - if use_router_api: - if enum_field_as_literal: - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - use_router_api, - enum_field_as_literal, - disable_timestamp=disable_timestamp, - ) - else: - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - use_router_api, - disable_timestamp=disable_timestamp, - ) - return generate_code( - input_name, - input_text, - output_dir, - template_dir, - model_path, - custom_visitors=custom_visitors, - disable_timestamp=disable_timestamp, - ) - - -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], - model_path: Optional[Path] = None, - use_router_api: Optional[str] = None, - enum_field_as_literal: Optional[str] = None, - custom_visitors: Optional[List[Path]] = [], - disable_timestamp: bool = False, -) -> None: - if not model_path: - model_path = MODEL_PATH - if not output_dir.exists(): - output_dir.mkdir(parents=True) - if not template_dir: - template_dir = BUILTIN_TEMPLATE_DIR - if use_router_api: - if enum_field_as_literal: - parser = OpenAPIParser(input_text, - enum_field_as_literal=enum_field_as_literal, - use_router_api=use_router_api) - else: - parser = OpenAPIParser(input_text, use_router_api=use_router_api) - else: - parser = OpenAPIParser(input_text) - 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( - template_dir if template_dir else f"{Path(__file__).parent}/template", - encoding="utf8", - ), - ) - - results: Dict[Path, str] = {} - code_formatter = CodeFormatter(PythonVersion.PY_38, Path().resolve()) - - template_vars: Dict[str, object] = {"info": parser.parse_info()} - visitors: List[Visitor] = [] - - # Load visitors - builtin_visitors = BUILTIN_VISITOR_DIR.rglob("*.py") - visitors_path = [*builtin_visitors, *(custom_visitors if custom_visitors else [])] - for visitor_path in visitors_path: - module = dynamic_load_module(visitor_path) - print("module_executed:", module) - module.__repr__() - if hasattr(module, "visit"): - visitors.append(module.visit) - else: - raise Exception(f"{visitor_path.stem} does not have any visit function") - - # Call visitors to build template_vars - for visitor in visitors: - visitor_result = visitor(parser, model_path) - template_vars = {**template_vars, **visitor_result} - # Convert from Tag Names to router_names - tags = use_router_api.split(",") - routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in tags] - template_vars = {**template_vars, "routers": routers, "tags": tags} - - for target in template_dir.rglob("*.*"): - relative_path = target.relative_to(template_dir) - if relative_path == Path("routers/routers.jinja2"): - for router, tag in zip(routers, tags): - template_vars["tag"] = tag.strip() - template = environment.get_template(str(relative_path)) - result = template.render(template_vars) - router_path = Path("routers", router).with_suffix(".jinja2") - results[router_path] = code_formatter.format_code(result) - else: - template = environment.get_template(str(relative_path)) - result = template.render(template_vars) - results[relative_path] = code_formatter.format_code(result) - - timestamp = datetime.now(timezone.utc).replace(microsecond=0).isoformat() - header = f"""\ -# generated by fastapi-codegen: -# filename: {Path(input_name).name}""" - if not disable_timestamp: - header += f"\n# timestamp: {timestamp}" - - for path, code in results.items(): - with output_dir.joinpath(path.with_suffix(".py")).open("wt") as file: - print(header, file=file) - print("", file=file) - print(code.rstrip(), file=file) - - header = f'''\ -# generated by fastapi-codegen: -# filename: {{filename}}''' - if not disable_timestamp: - header += f'\n# timestamp: {timestamp}' - - for path, body_and_filename in modules.items(): - body, filename = body_and_filename - if path is None: - file = None - else: - if not path.parent.exists(): - path.parent.mkdir(parents=True) - file = path.open('wt', encoding='utf8') - - print(header.format(filename=filename), file=file) - if body: - print('', file=file) - print(body.rstrip(), file=file) - - if file is not None: - file.close() - - -if __name__ == "__main__": - typer.run(main) diff --git a/docs/__parser.py b/docs/__parser.py deleted file mode 100644 index 96a7bac..0000000 --- a/docs/__parser.py +++ /dev/null @@ -1,455 +0,0 @@ -from __future__ import annotations - -import pathlib -import re -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 ( - 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 -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, - ResponseObject, -) -from datamodel_code_generator.types import DataType, DataTypeManager, StrictTypes -from pydantic import BaseModel - -RE_APPLICATION_JSON_PATTERN: Pattern[str] = re.compile(r'^application/.*json$') - - -class CachedPropertyModel(BaseModel): - class Config: - arbitrary_types_allowed = True - keep_untouched = (cached_property,) - - -class Response(BaseModel): - status_code: str - description: Optional[str] - contents: Dict[str, JsonSchemaObject] - - -class Request(BaseModel): - description: Optional[str] - contents: Dict[str, JsonSchemaObject] - required: bool - - -class UsefulStr(str): - @classmethod - def __get_validators__(cls) -> Any: - yield cls.validate - - @classmethod - def validate(cls, v: Any) -> Any: - return cls(v) - - @property - def snakecase(self) -> str: - return stringcase.snakecase(self) - - @property - def pascalcase(self) -> str: - return stringcase.pascalcase(self) - - @property - def camelcase(self) -> str: - return stringcase.camelcase(self) - - -class Argument(CachedPropertyModel): - name: UsefulStr - type_hint: UsefulStr - default: Optional[UsefulStr] - default_value: Optional[UsefulStr] - required: bool - - def __str__(self) -> str: - return self.argument - - @cached_property - def argument(self) -> str: - if self.default is None and self.required: - return f'{self.name}: {self.type_hint}' - return f'{self.name}: {self.type_hint} = {self.default}' - - -class Operation(CachedPropertyModel): - method: UsefulStr - path: UsefulStr - operationId: Optional[UsefulStr] - description: Optional[str] - summary: Optional[str] - parameters: List[Dict[str, Any]] = [] - responses: Dict[UsefulStr, Any] = {} - deprecated: bool = False - imports: List[Import] = [] - security: Optional[List[Dict[str, List[str]]]] = None - tags: Optional[List[str]] - arguments: str = '' - snake_case_arguments: str = '' - request: Optional[Argument] = None - response: str = '' - additional_responses: Dict[str, Dict[str, str]] = {} - return_type: str = '' - - @cached_property - def type(self) -> UsefulStr: - """ - backwards compatibility - """ - return self.method - - @cached_property - def root_path(self) -> UsefulStr: - paths = self.path.split("/") - return UsefulStr(paths[1] if len(paths) > 1 else '') - - @cached_property - def snake_case_path(self) -> str: - return re.sub( - r"{([^\}]+)}", lambda m: stringcase.snakecase(m.group()), self.path - ) - - @cached_property - def function_name(self) -> str: - if self.operationId: - name: str = self.operationId - else: - path = re.sub(r'/{|/', '_', self.snake_case_path).replace('}', '') - name = f"{self.type}{path}" - return stringcase.snakecase(name) - - -@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, - use_router_api: Optional[List[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], - ) - self.operations: Dict[str, Operation] = {} - self._temporary_operation: Dict[str, Any] = {} - self.imports_for_fastapi: Imports = Imports() - self.data_types: List[DataType] = [] - self.use_router_api: use_router_api.split(",") - - def parse_info(self) -> Optional[Dict[str, Any]]: - result = self.raw_obj.get('info', {}).copy() - servers = self.raw_obj.get('servers') - if servers: - result['servers'] = servers - return result or None - - 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, - parameters: ParameterObject, - snake_case: bool, - path: List[str], - ) -> Optional[Argument]: - orig_name = parameters.name - if snake_case: - name = stringcase.snakecase(parameters.name) - else: - name = parameters.name - - schema: Optional[JsonSchemaObject] = None - 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_ - data_type = self.parse_schema(name, schema, [*path, name]) - if not schema: - return None - - field = DataModelField( - name=name, - data_type=data_type, - required=parameters.required or parameters.in_ == ParameterLocation.path, - ) - - if orig_name != name: - 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: - 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, - default=default, # type: ignore - default_value=schema.default, - required=field.required, - ) - - 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] = [] - - parameters = self._temporary_operation.get('_parameters') - if parameters: - for parameter in 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: - arguments.append(request) - - positional_argument: bool = False - for argument in arguments: - if positional_argument and argument.required and argument.default is None: - argument.default = UsefulStr('...') - positional_argument = argument.required - - return arguments - - 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') - ) - elif media_type == 'application/octet-stream': - arguments.append( - Argument( - name='file', # type: ignore - type_hint='UploadFile', # type: ignore - required=True, - ) - ) - self.imports_for_fastapi.append( - Import.from_full_path("fastapi.UploadFile") - ) - self._temporary_operation['_request'] = arguments[0] if arguments else None - - def parse_responses( - self, - 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) - else: - data_type = DataType(type='None') - type_hint = data_type.type_hint # TODO: change to lazy loading - self._temporary_operation['response'] = type_hint - return_types = {type_hint: data_type} - for status_code, additional_responses in data_types.items(): - if status_code != '200' and additional_responses: # 200 is processed above - data_type = list(additional_responses.values())[0] - if data_type: - self.data_types.append(data_type) - type_hint = data_type.type_hint # TODO: change to lazy loading - self._temporary_operation.setdefault('additional_responses', {})[ - status_code - ] = {'model': type_hint} - return_types[type_hint] = data_type - if len(return_types) == 1: - return_type = next(iter(return_types.values())) - else: - return_type = DataType(data_types=list(return_types.values())) - if return_type: - self.data_types.append(return_type) - self._temporary_operation['return_type'] = return_type.type_hint - return data_types - - def parse_operation( - self, - raw_operation: Dict[str, Any], - path: List[str], - ) -> None: - 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['arguments'] = self.get_arguments( - snake_case=False, path=path - ) - self._temporary_operation['snake_case_arguments'] = self.get_arguments( - snake_case=True, path=path - ) - - self.operations[resolved_path] = Operation( - **raw_operation, - **self._temporary_operation, - path=f'/{path_name}', # type: ignore - method=method, # type: ignore - ) diff --git a/docs/__routers.jinja2 b/docs/__routers.jinja2 deleted file mode 100644 index aaec837..0000000 --- a/docs/__routers.jinja2 +++ /dev/null @@ -1,37 +0,0 @@ -from __future__ import annotations - -from fastapi import APIRouter -from fastapi import FastAPI - -{{imports}} - -router = APIRouter( - tags=['{{tag}}'] - ) - -{% for operation in operations %} -{% if operation.tags[0] == tag %} -@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} - {% if operation.additional_responses %} - , responses={ - {% for status_code, models in operation.additional_responses.items() %} - '{{ status_code }}': { - {% for key, model in models.items() %} - '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} - {% endfor %} - }{% if not loop.last %},{% endif %} - {% endfor %} - } - {% endif %} - {% if operation.tags%} - , tags={{operation.tags}} - {% endif %}) -def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: - {%- if operation.summary %} - """ - {{ operation.summary }} - """ - {%- endif %} - pass -{% endif %} -{% endfor %} \ No newline at end of file From b9e65448c4f23d672941e9135f1d76c1ba0f3fa8 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 3 Apr 2023 21:22:32 +0300 Subject: [PATCH 07/20] working version --- README.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/README.md b/README.md index e7752f2..a9ef9bd 100644 --- a/README.md +++ b/README.md @@ -352,9 +352,4 @@ visit: Visitor = custom_visitor ## License -fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license - - - - ---input swagger.yaml --output app --split-using-tags --exec-for-given-tags "Instance Data Group, List Files" \ No newline at end of file +fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license \ No newline at end of file From 09b2e75be489e51e886c6a67e1cd00c6170031f1 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 3 Apr 2023 21:23:36 +0300 Subject: [PATCH 08/20] working version --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a9ef9bd..0dd6635 100644 --- a/README.md +++ b/README.md @@ -352,4 +352,5 @@ visit: Visitor = custom_visitor ## License -fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license \ No newline at end of file +fastapi-code-generator is released under the MIT License. http://www.opensource.org/licenses/mit-license + From 783155a492fdcc41454a408f32f63cac9cd4139c Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Tue, 4 Apr 2023 10:49:42 +0300 Subject: [PATCH 09/20] working version. not tested yet --- tests/swagger.yaml | 3158 -------------------------------------------- 1 file changed, 3158 deletions(-) delete mode 100644 tests/swagger.yaml diff --git a/tests/swagger.yaml b/tests/swagger.yaml deleted file mode 100644 index 9e07fb7..0000000 --- a/tests/swagger.yaml +++ /dev/null @@ -1,3158 +0,0 @@ -openapi: 3.0.0 -info: - version: 1.0.15 - title: OnBoarding Portal API - description: | - Here data owners can define and store configurations for new processes, - modify existing ones and submit final configurations for execution. - [here comes some link]( https://elbitsystems.com). -paths: - /projects: - get: - tags: - - Projects - summary: Get All Existing Projects For Processing. - description: Retrieve list of all projects and its attributes. - operationId: getAllProjects - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: is_enabled - in: query - required: false - schema: - type: boolean - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/Project" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "500": - description: Internal Server Error - post: - tags: - - Projects - summary: Create New Processing Project. - description: Create new project to use in processing. - operationId: createNewProject - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProjectPartial" - description: Project attributes and parameters. - required: true - responses: - "201": - description: Created - headers: - project_id: - description: Id of newly created project. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /projects/{project_id}: - get: - tags: - - Projects - summary: Get Existing Project For Processing. - description: Retrieve project and all its attributes by providing project id. - operationId: getProjectById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: project_id - in: path - required: true - description: The uuid of the processing project. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/Project" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Projects - summary: Update Project. - description: Updating existing project and its properties in DB. - operationId: updateProjectById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: project_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProjectUpdatable" - description: Modified project object and attributes to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - project_id: - description: Id of updated project. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /haveownfiles: - post: - tags: - - List Files - summary: Get Indication if prefix have own direct files. - description: Get Indication if prefix have own direct files. - operationId: getOwnFilesIndication - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/StorageListingRequest" - description: Parameters required for bucket keys retrieval. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: boolean - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /listfiles: - post: - tags: - - List Files - summary: Get List Of Files In Landing Zone. - description: Retrieve list of files subjected to use in processing. - operationId: getFileListByUrl - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/StorageListingRequest" - description: Parameters required for bucket keys retrieval. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - type: string - example: Texts/README.txt - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /listcommonprefixes: - post: - tags: - - List Files - summary: Get List Of Common Files Prefixes. - description: Retrieve list of common files prefixes. - operationId: getAllCommonFilePrefixes - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/StorageListingRequest" - description: List of prefixes. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - type: string - example: landingzone - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /fileinventory: - post: - tags: - - List Files - summary: Get Data/Metadata inventory grouped by extensions. - description: Get Data/Metadata inventory grouped by extensions. - operationId: getFileInventoryByUrl - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/FileInventoryRequest" - description: Parameters required for inventory grouped by extensions retrieval. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: '#/components/schemas/FileinventoryResponse' - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processors: - post: - tags: - - Processors - summary: Create Processor. - description: Create new processor. - operationId: createProcessor - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessorPartial" - description: Processor object that needed to be added to the DB. - required: true - responses: - "201": - description: Created - headers: - processor_id: - description: Id of newly created processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Processors - summary: Get All Processors. - description: Retrieve list of all processors. - operationId: getAllProcessors - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: processor_type - in: query - required: false - description: Type of the processor. - schema: - $ref: "#/components/schemas/ProcessorType" - - name: processor_status - in: query - required: false - description: Status of the processor. - schema: - $ref: "#/components/schemas/ProcessorStatus" - - name: processor_visibility - in: query - required: false - description: Visibility of the processor. - schema: - $ref: "#/components/schemas/ProcessorVisibility" - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/Processor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "500": - description: Internal Server Error - /processors/{processor_id}: - get: - tags: - - Processors - summary: Get Processor. - description: Retrieve processor by providing process id. - operationId: getProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: processor_id - in: path - required: true - description: The uuid of the processor. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/Processor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Processors - summary: Update Processor. - description: Updating existing processor in DB. - operationId: updateProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: processor_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessorUpdatable" - description: Modified processor object to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - processor_id: - description: Id of updated processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/used_processors: - post: - tags: - - Used Processors - summary: Create Used Processor. - description: Create new used processor. - operationId: createUsedProcessor - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/UsedProcessorPartial" - description: Used processor object that needed to be added to the DB. - required: true - responses: - "201": - description: Created - headers: - used_processor_id: - description: Id of newly created used processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Used Processors - summary: Get All Used Processors. - description: Retrieve list of all used processors. - operationId: getAllUsedProcessors - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/UsedProcessor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "500": - description: Internal Server Error - /processes/{process_id}/used_processors/{used_processor_id}: - get: - tags: - - Used Processors - summary: Get Used Processor. - description: Retrieve used processor by providing used processor id. - operationId: getUsedProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: used_processor_id - in: path - required: true - description: The uuid of used processor. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/UsedProcessor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Used Processors - summary: Update Used Processor. - description: Updating existing used processor in DB. - operationId: updateUsedProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: used_processor_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/UsedProcessorUpdatable" - description: Modified used processor object to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - used_processor_id: - description: Id of updated used processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /used_processors/{used_processor_id}/instances/{instance_id}/instance_used_processors: - post: - tags: - - Instance Used Processors - summary: Create Instance Used Processor. - description: Create new instance used processor. - operationId: createInstanceUsedProcessor - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: used_processor_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/InstanceUsedProcessorPartial" - description: Instance used processor object that needed to be added to the DB. - required: true - responses: - "201": - description: Created - headers: - used_processor_instance_id: - description: Id of newly created instance used processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Instance Used Processors - summary: Get All Instance Used Processors. - deprecated: true - description: Retrieve list of all instance used processors. - operationId: getAllInstancesUsedProcessors - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: used_processor_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/InstanceUsedProcessor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /used_processors/{used_processor_id}/instances/{instance_id}/instance_used_processors/{used_processor_instance_id}: - get: - tags: - - Instance Used Processors - summary: Get Instance Used Processor. - description: Retrieve instance used processor by providing used processor instance id. - operationId: getInstanceUsedProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: used_processor_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: used_processor_instance_id - in: path - required: true - description: The uuid of instance used processor. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/InstanceUsedProcessor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Instance Used Processors - summary: Update Instance Used Processor. - description: Updating existing instance used processor in DB. - operationId: updateInstanceUsedProcessorById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: used_processor_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: used_processor_instance_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/InstanceUsedProcessorPartial" - description: Modified instance used processor object to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - used_processor_instance_id: - description: Id of updated instance used processor. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes: - post: - tags: - - Process Blueprint - summary: Create Process Blueprint. - description: Create new process blueprint. - operationId: createProcessBlueprint - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessBlueprintPartial" - description: Process blueprint object that needed to be added to the DB. - required: true - responses: - "201": - description: Created - headers: - process_id: - description: Id of newly created process blueprint. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Process Blueprint - summary: Get All Process Blueprints. - description: Retrieve list of all process blueprints. - operationId: getAllProcessBlueprints - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: project_id - in: query - required: false - description: Project id - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessBlueprint" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "500": - description: Internal Server Error - /processes/{process_id}: - get: - tags: - - Process Blueprint - summary: Get Process Blueprint. - description: Retrieve blueprint process by providing process id. - operationId: getProcessBlueprintById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - description: The uuid of the process blueprint. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/ProcessBlueprint" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Process Blueprint - summary: Update Process Blueprint. - description: Updating existing process blueprint in DB. - operationId: updateProcessBlueprintById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessBlueprintUpdatable" - description: Modified process blueprint object to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - process_id: - description: Id of updated process. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "405": - description: Method Not Allowed - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/data_groups: - post: - tags: - - Process Data Group - summary: Add Data Group To Process Blueprint. - description: Creates and adds new data group to existing blueprint of the process by - providing process id. - operationId: createProcessDataGroups - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" - description: Data groups of process blueprint that needed to be added to the DB. - required: true - responses: - "201": - description: Created - headers: - data_group_id: - description: Id of newly created data group. - schema: - type: string - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Process Data Group - summary: Get All Data Groups Of Process Blueprint. - description: Retrieve all data groups of existing process blueprint. - operationId: getAllProcessDataGroups - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: data_group_type - in: query - required: false - schema: - $ref: "#/components/schemas/DataGroupType" - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessBlueprintDataGroup" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/data_groups/{data_group_id}: - get: - tags: - - Process Data Group - summary: Get Data Group Of Process Blueprint. - description: Retrieve data group of existing process blueprint by providing process - id and data group id. - operationId: getProcessDataGroupById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: data_group_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/ProcessBlueprintDataGroup" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Process Data Group - summary: Update Data Group Of Process Blueprint. - description: Updating data group of existing process blueprint in DB. - operationId: updateDataGroupById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: data_group_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" - description: Modified data group object to update in DB. - required: true - responses: - "200": - description: Successful response. - headers: - data_group_id: - description: Id of updated process data group. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "405": - description: Method Not Allowed - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances: - post: - tags: - - Process Instance - summary: Create Process Instance. - description: Create new process instance. - operationId: createProcessInstance - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessInstancePartial" - description: Process instance object that needed to be added to DB. - required: true - responses: - "201": - description: Created - headers: - instance_id: - description: Id of newly created process instance. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Process Instance - summary: Get All Process Instances. - description: Retrieve list of all process instances. - operationId: getAllProcessInstances - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessInstance" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances/{instance_id}: - get: - tags: - - Process Instance - summary: Get Process Instance. - description: Retrieve instance of a process by providing process id and instance id. - operationId: getProcessInstanceById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - description: The uuid of the process blueprint. - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - description: The uuid of instance of a process. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/ProcessInstance" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Process Instance - summary: Update Process Instance. - description: Updating existing process instance in DB. - operationId: updateProcessInstanceById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessInstanceUpdatable" - description: Modified process instance object and data groups to update the DB. - required: true - responses: - "200": - description: Successful response. - headers: - instance_id: - description: Id of updated instance. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "405": - description: Method Not Allowed - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances/{instance_id}/instance_used_processors: - get: - tags: - - Instance Used Processors - summary: Get All Instance Used Processors - description: | - Get all instance used processor by providing instance id and process id. - operationId: getAllInstanceUsedProcessors - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/InstanceUsedProcessor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances/{instance_id}/runs: - get: - tags: - - Process Instance - summary: Get Runs Of Process Instances. - description: | - Get runs of process instance ordered by date submitted on - in descending order. - operationId: getInstanceRunsSortedBySubmittedOn - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: run_type - in: query - required: false - schema: - $ref: "#/components/schemas/RunType" - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessInstanceRun" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /process_instance_runs: - get: - tags: - - Process Instance - summary: Get Runs Of Process Instances By Params. - description: | - Get runs of process instance created between requested dates. - operationId: getInstanceRunsByRequestedParams - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: from_created_date - in: query - required: false - schema: - type: string - format: date-time - - name: to_created_date - in: query - required: false - schema: - type: string - format: date-time - - name: project_id - in: query - required: false - schema: - type: string - format: uuid - - name: process_id - in: query - required: false - schema: - type: string - format: uuid - - name: instance_id - in: query - required: false - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessInstanceRunSelected" - "400": - description: Bad Request - "403": - description: Forbidden - "422": - description: Validation Error - "500": - description: Internal Server Error - /data_group/{data_group_id}/instances/{instance_id}/instance_data_groups: - post: - tags: - - Instance Data Group - summary: Create Instance Data Group Of Process Instance. - description: Create new instance data group and add it to existing process instance. - operationId: createInstanceDataGroup - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: data_group_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" - description: Instance data group object that needed to be added to DB. - required: true - responses: - "201": - description: Created - headers: - data_group_instance_id: - description: Id of newly created instance data group. - schema: - type: string - "400": - description: Bad Request - "403": - description: Forbidden - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - get: - tags: - - Instance Data Group - summary: Get All Instance Data Groups Of Process Instance. - deprecated: true - description: Retrieve instance data group of existing process instance by - providing data group id and instance id. - operationId: getInstanceDataGroup - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: data_group_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessInstanceDataGroup" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /data_group/{data_group_id}/instances/{instance_id}/instance_data_groups/{data_group_instance_id}: - get: - tags: - - Instance Data Group - summary: Get Instance Data Group Of Process Instance. - description: Retrieve instance data group of existing process instance by providing - data group id, instance id and requested instance data group id. - operationId: getInstanceDataGroupById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: data_group_id - in: path - required: true - description: The uuid of data group. - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - description: The uuid of process instance. - schema: - type: string - format: uuid - - name: data_group_instance_id - in: path - required: true - description: The uuid of instance data group. - schema: - type: string - format: uuid - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/ProcessInstanceDataGroup" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - put: - tags: - - Instance Data Group - summary: Update Instance Data Group Of Process Instance. - description: Update instance data group of existing process instance by providing - data group id, instance id and instance data group id. - operationId: updateInstanceDataGroupById - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: data_group_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: data_group_instance_id - in: path - required: true - schema: - type: string - format: uuid - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" - description: Modified instance data group of existing process instance. - required: true - responses: - "200": - description: Successful response. - headers: - data_group_instance_id: - description: Id of updated instance data group. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "405": - description: Method Not Allowed - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances/{instance_id}/submit/{run_type}: - get: - tags: - - Process Instance - summary: Verify Eligibility Of Instance For Submitting. - description: Verify if instance eligible to be submitted for run of specific type. - operationId: isProcessInstanceSubmittable - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: run_type - in: path - required: true - schema: - $ref: "#/components/schemas/RunType" - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: boolean - - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - post: - tags: - - Process Instance - summary: Submit Execution Request For Finalized Process Instance. - description: Submitting predefined process instance along with all associated - instance data groups to the server for further execution. - operationId: submitProcessInstance - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: run_type - in: path - required: true - schema: - $ref: "#/components/schemas/RunType" - responses: - "202": - description: Accepted - headers: - run_id: - description: Id of submitted run. - schema: - type: string - format: uuid - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "405": - description: Method Not Allowed - "409": - description: Database Conflict - "422": - description: Validation Error - "500": - description: Internal Server Error - /processes/{process_id}/instances/{instance_id}/instance_data_groups: - get: - tags: - - Instance Data Group - summary: Get All Instance Data Groups Of Process Instance. - description: Retrieve all instance data groups of existing process instance by - providing data group id, instance id and requested data group type. - operationId: getAllInstanceDataGroups - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - - name: process_id - in: path - required: true - schema: - type: string - format: uuid - - name: instance_id - in: path - required: true - schema: - type: string - format: uuid - - name: data_group_type - in: query - required: false - description: Type of data group. - schema: - $ref: "#/components/schemas/DataGroupType" - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/ProcessInstanceDataGroup" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processing_chain/next_chainable_processors: - post: - tags: - - Process Blueprint Processing Chain - summary: Get All Next Chainable Processors. - description: Retrieve all next chainable processors by providing process id. - operationId: getNextChainableProcessors - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/NextChainableProcessorRequest" - description: Parameters required for retrieving next chainable processors. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - type: array - items: - $ref: "#/components/schemas/Processor" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processing_chain/next_chainable_datagroup: - post: - tags: - - Process Blueprint Processing Chain - summary: Get Next Chainable Data Group. - description: Retrieve next chainable data group by providing process id. - operationId: getNextChainableDatagroup - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/NextChainableDatagroupRequest" - description: Parameters required for retrieving next chainable datagroup. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/NextChainableDatagroupResponse" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error - /processing_chain/next_chainable_instance_datagroup: - post: - tags: - - Process Instance Processing Chain - summary: Get Next Chainable Data Group. - description: Retrieve next chainable data group by providing process id. - operationId: getNextChainableInstanceDatagroup - parameters: - - name: X-User - in: header - required: true - schema: - type: string - - name: X-User-Groups - in: header - required: true - schema: - type: string - requestBody: - content: - application/json: - schema: - $ref: "#/components/schemas/NextChainableInstanceDatagroupRequest" - description: Parameters required for retrieving next chainable datagroup. - responses: - "200": - description: Successful response. - content: - "*/*": - schema: - $ref: "#/components/schemas/NextChainableInstanceDatagroupResponse" - "400": - description: Bad Request - "403": - description: Forbidden - "404": - description: Not Found - "422": - description: Validation Error - "500": - description: Internal Server Error -servers: - - url: / - - url: /secure/api/v1/onboardingportalapi - - url: http://localhost:8080/ - - url: http://onboardingportalapi:8080/ - - url: http://onboardingportalapi.daita.devbit.io:8081/ - -components: - schemas: - FileinventoryResponse: - type: object - properties: - common_md: - type: boolean - description: indication for common.md.json file occurrence in directory - example: false - partial_md: - type: boolean - description: indication for partial.md.json file occurrence in directory - example: false - extensions: - type: array - description: list of extensions and quantities of files aggregations by extension - items: - type: object - properties: - ext: - type: string - description: extension of data files - example: "mpeg" - data_count: - type: integer - description: quantity of data files in directory aggregated by extension - example: 39 - md_count: - type: integer - description: quantity of metadata files in directory aggregated by extension - example: 39 - common_ext_md: - type: boolean - description: indication for common_{ext}.md.json file occurrence in directory - example: false - partial_ext_md: - type: boolean - description: indication for partial_{ext}.md.json file occurrence in directory - example: true - required: - - ext - - data_count - - md_count - - common_ext_md - - partial_ext_md - collisions_count: - type: integer - description: quantity of collisions by filename in destination bucket directory - example: 1 - collisions_samples: - type: array - description: samples of filenames having collision in destination bucket directory - items: - type: string - description: filename - example: "test_flight_001.mpeg" - required: - - common_md - - partial_md - - extensions - - collisions_count - - collisions_samples - - NextChainableDatagroupRequest: - type: object - properties: - processor_id: - type: string - format: uuid - example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d - input_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - suppl_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - required: - - processor_id - - input_datagroup_manifest - - suppl_datagroup_manifest - NextChainableDatagroupResponse: - type: object - properties: - output_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - reduce_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - required: - - output_datagroup_manifest - - reduce_datagroup_manifest - NextChainableInstanceDatagroupRequest: - type: object - properties: - processor_id: - type: string - format: uuid - example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d - input_datagroup: - $ref: "#/components/schemas/InstanceDataGroupValues" - suppl_datagroup: - $ref: "#/components/schemas/InstanceDataGroupValues" - required: - - processor_id - - input_datagroup - - suppl_datagroup - NextChainableInstanceDatagroupResponse: - type: object - properties: - output_datagroup: - $ref: "#/components/schemas/InstanceDataGroupValues" - reduce_datagroup: - $ref: "#/components/schemas/InstanceDataGroupValues" - required: - - output_datagroup - - reduce_datagroup - NextChainableProcessorRequest: - type: object - properties: - input_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - suppl_datagroup_manifest: - $ref: "#/components/schemas/ExtractManifest" - required: - - input_datagroup_manifest - - suppl_datagroup_manifest - RunType: - type: string - enum: - - validation - - processing - - ingestion - example: validation - ProcessorType: - type: string - enum: - - validator - - extractor - - ingestor - - processor - - reshape - example: extractor - ProcessorStatus: - type: string - enum: - - draft - - testrun - - enabled - - obsolete - - disabled - example: enabled - ProcessorVisibility: - type: string - enum: - - system - - private - - project - - groups - - public - example: public - DataGroupType: - type: string - enum: - - initial - - existing - - intermediate - - final - example: initial - FileInventoryRequest: - allOf: - - $ref: "#/components/schemas/StorageListingRequest" - - properties: - raw_zone_bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: test-raw-zone - description: Base URL of the bucket. - required: - - raw_zone_bucket - - StorageListingRequest: - type: object - properties: - access_key: - type: string - pattern: ^[A-Z0-9]{20}$ - example: ABCDEFGHIJKLMNOPQRST - description: Secret access key provided by client for authentication - purposes. - secret_access_key: - type: string - pattern: ^[a-zA-Z0-9/\+]{40}$ - example: 6GLuEBb8e35ceyH6GLuEBb8e35ceyH/+6GLuEBb8 - description: Secret access key provided by client for authentication - purposes. - region_name: - type: string - example: eu-west-1 - description: AWS Region. - endpoint_override_url: - type: string - format: uri - example: http://minio:9000 - description: Overridden storage URL - bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: test-landing-zone - description: Base URL of the bucket. - prefix: - type: string - example: objectstorage - description: Prefix of the keys block. - required: - - access_key - - secret_access_key - - bucket - Processor: - allOf: - - properties: - processor_id: - type: string - format: uuid - example: dca74c6d-91cc-4c6d-a7f7-a7f7bc234c6d - - $ref: "#/components/schemas/ProcessorPartial" - - $ref: "#/components/schemas/ChangeTrackingBlock" - required: - - processor_id - ProcessorPartial: - allOf: - - properties: - project_id: - type: string - format: uuid - example: dca74c6d-91cc-4c6d-a791-a7f7bc291ccd - - $ref: "#/components/schemas/ProcessorUpdatable" - required: - - project_id - ProcessorUpdatable: - allOf: - - properties: - parent_processor_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-a7f7bc2391dd - processor_name: - type: string - example: Extract Header - processor_version: - type: string - example: 2.3.2.1 - multiplicity: - type: string - enum: - - single - - multiple - example: multiple - description: - type: string - example: Extracting column names from header of the file. - processor_type: - $ref: "#/components/schemas/ProcessorType" - encapsulation: - type: string - enum: - - docker - - wheel - - maven - example: wheel - artifact_ref: - type: string - example: land/video_metadata:1.3.0.2 - entrypoint: - type: string - example: SomeTimesIsNotExitOne - processor_status: - $ref: "#/components/schemas/ProcessorStatus" - processor_visibility: - $ref: "#/components/schemas/ProcessorVisibility" - processor_manifest: - $ref: "#/components/schemas/ProcessorManifest" - default_env_parameters: - type: object - description: Unbound empty object describing default environmental parameters.TBD.FFU. - default_program_arguments: - type: object - description: Unbound empty object describing default program arguments.TBD.FFU. - - required: - - processor_name - - processor_version - - multiplicity - - processor_type - - encapsulation - - artifact_ref - - processor_status - - processor_visibility - - default_env_parameters - - default_program_arguments - - UsedProcessor: - allOf: - - properties: - used_processor_id: - type: string - format: uuid - example: d391ddf6-91cc-4c6d-a7f7-91cc91cc91cc - process_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-91cc91cc91cc - - $ref: "#/components/schemas/UsedProcessorPartial" - required: - - used_processor_id - - process_id - UsedProcessorPartial: - allOf: - - properties: - processor_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-91cc91cc91cc - - $ref: "#/components/schemas/UsedProcessorUpdatable" - required: - - processor_id - UsedProcessorUpdatable: - properties: - override_env_parameters: - type: object - description: Unbound empty object describing overridden environmental - parameters.TBD.FFU. - override_program_arguments: - type: object - description: Unbound empty object describing overridden program arguments.TBD.FFU. - required: - - override_env_parameters - - override_program_arguments - InstanceUsedProcessor: - allOf: - - properties: - used_processor_instance_id: - type: string - format: uuid - example: d391ddf6-91cc-4c6d-a7f7-91cc9191cccc - instance_id: - type: string - format: uuid - example: a7f7b5f6-91cc-b5f6-a7f7-91cc91cc91cc - used_processor_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-a7f7bc2391dd - - $ref: "#/components/schemas/InstanceUsedProcessorPartial" - required: - - used_processor_instance_id - - used_processor_id - - instance_id - InstanceUsedProcessorPartial: - properties: - override_program_arguments: - type: object - description: Unbound empty object describing overridden program arguments.TBD.FFU. - override_env_parameters: - type: object - description: Unbound empty object describing overridden environmental - parameters.TBD.FFU. - required: - - override_program_arguments - - override_env_parameters - ProcessBlueprint: - allOf: - - properties: - process_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-2989bc2342bb - parent_process_id: - type: string - format: uuid - example: 5adda535-6360-461e-a245-5c74b2eaac11 - - $ref: "#/components/schemas/ProcessBlueprintPartial" - - $ref: "#/components/schemas/ChangeTrackingBlock" - required: - - process_id - ProcessBlueprintPartial: - allOf: - - properties: - project_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-2989bc235c74 - - $ref: "#/components/schemas/ProcessBlueprintUpdatable" - required: - - project_id - ProcessBlueprintUpdatable: - allOf: - - properties: - process_name: - type: string - example: CopyFiles - process_version: - type: string - example: 1.0.0.0 - description: - type: string - example: Here comes some text to describe the process blueprint. - process_status: - type: string - enum: - - draft - - testrun - - enabled - - obsolete - - disabled - example: enabled - process_visibility: - type: string - enum: - - private - - project - - groups - - public - example: public - data_processor_dag: - $ref: "#/components/schemas/DataProcessorDAG" - - required: - - process_name - - process_version - - data_processor_dag - - ProcessInstance: - allOf: - - properties: - instance_id: - type: string - format: uuid - example: 70bdcbc7-3dbb-47da-a425-dfc110410892 - process_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-2989bc2342bb - - $ref: "#/components/schemas/ProcessInstancePartial" - - $ref: "#/components/schemas/ChangeTrackingBlock" - required: - - instance_id - - process_id - ProcessInstanceUpdatable: - allOf: - - properties: - description: - type: string - example: Here comes some text to describe the process instance. - - $ref: "#/components/schemas/InitialMetadata" - ProcessInstancePartial: - allOf: - - properties: - project_storage_spec: - type: string - format: uuid - example: 70bdcbc7-3dbb-47da-a425-dfc110dfc112 - - $ref: "#/components/schemas/ProcessInstanceUpdatable" - required: - - project_storage_spec - InitialMetadata: - properties: - initial_metadata: - type: object - description: Unbound empty object describing initial metadata.TBD.FFU. - required: - - initial_metadata - ChangeTrackingBlock: - properties: - created_by: - type: string - example: UserA - created_on: - type: string - format: date-time - example: 2022-03-05T14:20:00.245Z - last_modified_by: - type: string - example: UserA - last_modified_on: - type: string - format: date-time - example: 2022-03-05T14:20:00.245Z - required: - - created_by - - created_on - ProcessBlueprintDataGroup: - allOf: - - properties: - data_group_id: - type: string - format: uuid - example: 85b285e0-8bed-4271-aaef-a4a09aa56fae - process_id: - type: string - format: uuid - example: a4a09ae0-8bed-aaef-aaef-a4a0aaefaaef - - $ref: "#/components/schemas/ProcessBlueprintDataGroupPartial" - required: - - data_group_id - ProcessBlueprintDataGroupPartial: - type: object - properties: - group_name: - type: string - example: vis_thermal_8bit_triplets/vis/bmp - metadata_extractor: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa28bba - data_group_type: - $ref: "#/components/schemas/DataGroupType" - data_group_manifest: - $ref: "#/components/schemas/ExtractManifest" - description: - type: string - example: Here comes some text to describe the data group. - required: - - group_name - - data_group_type - - data_group_manifest - ProcessInstanceDataGroup: - type: object - allOf: - - properties: - data_group_instance_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa28bed - data_group_id: - type: string - format: uuid - example: 7f7285e0-8bed-8bed-aaef-a4a09aa2aaef - instance_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa28bba - data_is_ingested: - type: boolean - example: false - metadata_schema_is_valid: - type: boolean - example: false - validated_data_file_count: - type: integer - example: 1 - ingested_data_file_count: - type: integer - example: 2 - - $ref: "#/components/schemas/ProcessInstanceDataGroupPartial" - required: - - data_group_instance_id - - data_group_id - - instance_id - ProcessInstanceDataGroupPartial: - type: object - properties: - data_file_count: - type: integer - example: 3 - metadata_file_count: - type: integer - example: 2 - data_group_values: - $ref: "#/components/schemas/InstanceDataGroupValues" - required: - - data_group_values - ProcessInstanceRun: - type: object - properties: - run_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa23e1a - instance_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45ead - run_type: - $ref: "#/components/schemas/RunType" - dag_run_id: - type: string - example: DR-0003 - submitted_on: - type: string - format: date-time - example: 2022-03-06T09:48:13.236Z - submitted_by: - type: string - example: UserA - started_on: - type: string - format: date-time - example: 2022-03-07T09:52:01.187Z - failed_on: - type: string - format: date-time - example: 2022-03-07T10:15:00.201Z - finished_on: - type: string - format: date-time - example: 2022-03-07T10:15:00.201Z - required: - - run_id - - instance_id - - submitted_by - - submitted_on - - run_type - ProcessInstanceRunSelected: - type: object - properties: - process_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa23e1a - instance_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45ead - project_id: - type: string - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc - process_name: - type: string - example: Convert files - process_version: - type: string - example: 1.4.1.7 - created_on: - type: string - format: date-time - example: 2022-03-06T09:48:13.236Z - created_by: - type: string - example: UserA - validation_last_run_id: - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc - validation_last_run_status: - type: string - example: Finished - ingestion_last_run_id: - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc - ingestion_last_run_status: - type: string - example: Failed - processing_last_run_id: - format: uuid - example: 7f7285e0-8bed-4271-aaef-a4a09aa45abc - processing_last_run_status: - type: string - example: Finished - is_processing_dag: - type: boolean - example: true - is_initial_datagroups: - type: boolean - example: false - total_data_file_count: - type: integer - example: 3 - total_validated_data_file_count: - type: integer - example: 2 - total_ingested_data_file_count: - type: integer - example: 1 - - required: - - process_id - - instance_id - - process_name - - process_version - - created_on - - created_by - - is_processing_dag - - is_initial_datagroups - - Project: - allOf: - - properties: - project_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-2989bc2332ea - project_storage_spec_id: - type: string - format: uuid - example: dca7b5f6-91cc-4c6d-a7f7-2989bc1745de - valid_from: - type: string - format: date-time - example: 2022-05-07T12:13:00.201Z - valid_until: - type: string - format: date-time - example: 2022-05-13T17:19:00.201Z - - $ref: "#/components/schemas/ProjectPartial" - - $ref: "#/components/schemas/ChangeTrackingBlock" - required: - - project_id - - valid_from - - valid_until - ProjectPartial: - allOf: - - properties: - project_ref_id: - type: string - example: n312 - - $ref: "#/components/schemas/ProjectUpdatable" - required: - - project_ref_id - ProjectUpdatable: - allOf: - - properties: - project_name: - type: string - example: Moving Vehicles - description: - type: string - example: Description of the project. - is_enabled: - type: boolean - example: true - ldap_groups: - type: array - items: - type: string - example: administrators - landing_zone_bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: no2227764-landing-zone - raw_zone_bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: no2227764-raw-zone - processed_zone_bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: no2227764-processed-zone - archive_zone_bucket: - type: string - pattern: (?!(^xn--|-s3alias$))^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$ - example: no2227764-archive-zone - endpoint_override_url: - type: string - format: uri - example: http://minio:9000 - region_name: - type: string - example: us-east-1 - account_id: - type: string - example: "123456789" - account_user: - type: string - example: minioadmin - account_password: - type: string - example: minioadmin - storage_type: - $ref: "#/components/schemas/StorageType" - required: - - project_name - - is_enabled - - landing_zone_bucket - - raw_zone_bucket - - processed_zone_bucket - - archive_zone_bucket - - account_user - - account_password - ProcessorManifest: - type: object - properties: - inputManifest: - $ref: "#/components/schemas/ExtractManifest" - supplManifest: - $ref: "#/components/schemas/ExtractManifest" - outputManifest: - $ref: "#/components/schemas/ReplaceManifest" - reduceManifest: - $ref: "#/components/schemas/ReplaceManifest" - inputMetadata: - $ref: "#/components/schemas/FlagManifest" - inputUpdateMetadata: - $ref: "#/components/schemas/FlagManifest" - supplMetadata: - $ref: "#/components/schemas/FlagManifest" - outputMetadata: - $ref: "#/components/schemas/FlagManifest" - reduceMetadata: - $ref: "#/components/schemas/FlagManifest" - inputLineage: - $ref: "#/components/schemas/FlagManifest" - supplLineage: - $ref: "#/components/schemas/FlagManifest" - outputLineage: - $ref: "#/components/schemas/FlagManifest" - reduceLineage: - $ref: "#/components/schemas/FlagManifest" - additionalProperties: false - required: - - inputManifest - - supplManifest - - outputManifest - - reduceManifest - - inputMetadata - - inputUpdateMetadata - - supplMetadata - - outputMetadata - - reduceMetadata - - inputLineage - - supplLineage - - outputLineage - - reduceLineage - ExtractManifest: - type: array - items: - type: string - example: camera/(.*).mp4 - description: Regular expression with capturing groups to match extract filename elements - ReplaceManifest: - type: array - items: - type: string - example: camera/#1$1.mp3 - description: | - Expression with tuple index and capturing group to replace - filename with extracted elements - FlagManifest: - type: array - items: - type: boolean - example: true - DataProcessorDAG: - type: array - items: - oneOf: - - $ref: "#/components/schemas/InputLink" - - $ref: "#/components/schemas/OutputLink" - - $ref: "#/components/schemas/ControlLink" - InputLink: - type: object - properties: - inputDataGroups: - type: array - items: - type: string - format: uuid - supplDataGroups: - type: array - items: - type: string - format: uuid - usedProcessor: - type: string - format: uuid - additionalProperties: false - required: - - inputDataGroups - - supplDataGroups - - usedProcessor - OutputLink: - type: object - properties: - usedProcessor: - type: string - format: uuid - outputDataGroups: - type: array - items: - type: string - format: uuid - reduceDataGroups: - type: array - items: - type: string - format: uuid - additionalProperties: false - required: - - usedProcessor - - outputDataGroups - - reduceDataGroups - ControlLink: - type: object - properties: - fromUsedProcessor: - type: string - format: uuid - toUsedProcessor: - type: string - format: uuid - additionalProperties: false - required: - - fromUsedProcessor - - toUsedProcessor - StorageType: - type: string - enum: - - netapp - - minio - - aws - example: minio - InstanceDataGroupValues: - type: array - items: - type: array - items: - type: string - example: camera/*image*.MP4 \ No newline at end of file From a7b93fc47147b93668138fd58018213fc06d1052 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Tue, 4 Apr 2023 17:02:37 +0300 Subject: [PATCH 10/20] README.md documentation edited --- README.md | 385 ++++++++++++++++++++++++++++++++++++++++++++++++++- swagger.yaml | 129 +++++++++++++++++ 2 files changed, 513 insertions(+), 1 deletion(-) create mode 100644 swagger.yaml diff --git a/README.md b/README.md index 0dd6635..2ba384b 100644 --- a/README.md +++ b/README.md @@ -36,11 +36,12 @@ Options: -o, --output PATH [required] -t, --template-dir PATH -m, --model-file Specify generated model file path + name, if not default to models.py + -r, --generate-routers Generate modular api with multiple routers using RouterAPI (for bigger applications). + --specify-tags Use along with --generate-routers to generate specific routers from given list of tags. -c, --custom-visitors PATH - A custom visitor that adds variables to the template. --install-completion Install completion for the current shell. --show-completion Show completion for the current shell, to copy it or customize the installation. - --help Show this message and exit. ``` @@ -313,6 +314,79 @@ def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operati ``` +### modular_template +`modular_template/main.jinja2`: +```jinja +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import {{ routers | join(", ") }} + +app = FastAPI( + {% if info %} + {% for key,value in info.items() %} + {% set info_value= value.__repr__() %} + {{ key }} = {{info_value}}, + {% endfor %} + {% endif %} + ) + +{% for router in routers -%} +app.include_router({{router}}.router) +{% endfor -%} + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} +``` + +`modular_template/routers.jinja2`: +```jinja +from __future__ import annotations + +from fastapi import APIRouter +from fastapi import FastAPI + +from ..dependencies import * + +router = APIRouter( + tags=['{{tag}}'] + ) + +{% for operation in operations %} +{% if operation.tags[0] == tag %} +@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} + {% if operation.additional_responses %} + , responses={ + {% for status_code, models in operation.additional_responses.items() %} + '{{ status_code }}': { + {% for key, model in models.items() %} + '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} + {% endfor %} + }{% if not loop.last %},{% endif %} + {% endfor %} + } + {% endif %} + {% if operation.tags%} + , tags={{operation.tags}} + {% endif %}) +def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: + {%- if operation.summary %} + """ + {{ operation.summary }} + """ + {%- endif %} + pass +{% endif %} +{% endfor %} +``` + +`modular_template/dependencies.jinja2`: +```jinja +{{imports}} +``` + ## Custom Visitors Custom visitors allow you to pass custom variables to your custom templates. @@ -346,6 +420,315 @@ def custom_visitor(parser: OpenAPIParser, model_path: Path) -> Dict[str, object] visit: Visitor = custom_visitor ``` +### Multiple Files using APIRouter (For Bigger Applications) +``` +├── app # "app" is a Root directory +│ ├── main.py # "main" module +│ ├── models.py # "models" of the application +│ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies +│ └── routers # "routers" is a "app subpackage" +│ │ ├── fat_cats.py # "cats" submodule, e.g. import app.routers.fat_cats +│ │ └── slim_dogs.py # "dogs" submodule, e.g. import app.routers.slim_dogs +``` +**_Generate main aside with all of its routers_**: +```bash +$ fastapi-codegen --input swagger.yaml --output app --generate-routers +``` + +**_Regenerate specific routers_**: +```bash +$ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify-tags "Slim Dogs, Fat Cats" +``` + + +
+swagger.yaml +
+
+openapi: "3.0.0"
+info:
+  version: 1.0.0
+  title: Swagger Petstore
+  license:
+    name: MIT
+servers:
+  - url: http://petstore.swagger.io/v1
+paths:
+  /cats:
+    get:
+      summary: List All Fat Cats
+      operationId: listFatCats
+      tags:
+        - Fat Cats
+      parameters:
+        - name: limit
+          in: query
+          description: How many items to return at one time (max 100)
+          required: false
+          schema:
+            type: integer
+      responses:
+        '200':
+          description: An array of fat cats
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/FatCats"
+    post:
+      summary: Create a Fat Cat
+      operationId: createFatCats
+      tags:
+        - Fat Cats
+      responses:
+        '201':
+          description: Null response
+  /cats/{catId}:
+    get:
+      summary: Info For a Specific Cat
+      operationId: showCatById
+      tags:
+        - Fat Cats
+      parameters:
+        - name: catId
+          in: path
+          required: true
+          description: The id of the cat to retrieve
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Expected response to a valid request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/FatCats"
+  /dogs:
+    get:
+      summary: List All Slim Dogs
+      operationId: listSlimDogs
+      tags:
+        - Slim Dogs
+      parameters:
+        - name: limit
+          in: query
+          description: How many items to return at one time (max 100)
+          required: false
+          schema:
+            type: integer
+      responses:
+        '200':
+          description: An array of slim dogs
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/SlimDogs"
+    post:
+      summary: Create a Slim Dog
+      operationId: createSlimDogs
+      tags:
+        - Slim Dogs
+      responses:
+        '201':
+          description: Null response
+  /dogs/{dogId}:
+    get:
+      summary: Info For a Specific Dog
+      operationId: showDogById
+      tags:
+        - Slim Dogs
+      parameters:
+        - name: dogId
+          in: path
+          required: true
+          description: The id of the dog to retrieve
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Expected response to a valid request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/SlimDogs"
+components:
+  schemas:
+    Pet:
+      required:
+        - id
+        - name
+      properties:
+        id:
+          type: integer
+        name:
+          type: string
+        tag:
+          type: string
+    FatCats:
+      type: array
+      description: list of fat cats
+      items:
+        $ref: "#/components/schemas/Pet"
+    SlimDogs:
+      type: array
+      description: list of slim dogs
+      items:
+        $ref: "#/components/schemas/Pet"
+
+
+
+ +`app/main.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import fat_cats, slim_dogs + +app = FastAPI( + version='1.0.0', + title='Swagger Petstore', + license={'name': 'MIT'}, + servers=[{'url': 'http://petstore.swagger.io/v1'}], +) + +app.include_router(fat_cats.router) +app.include_router(slim_dogs.router) + + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} +``` + +`app/models.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Pet(BaseModel): + id: int + name: str + tag: Optional[str] = None + + +class FatCats(BaseModel): + __root__: List[Pet] = Field(..., description='list of fat cats') + + +class SlimDogs(BaseModel): + __root__: List[Pet] = Field(..., description='list of slim dogs') +``` + +`app/routers/fat_cats.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from fastapi import APIRouter, FastAPI + +from ..dependencies import * + +router = APIRouter(tags=['Fat Cats']) + + +@router.get('/cats', response_model=FatCats, tags=['Fat Cats']) +def list_fat_cats(limit: Optional[int] = None) -> FatCats: + """ + List All Fat Cats + """ + pass + + +@router.post('/cats', response_model=None, tags=['Fat Cats']) +def create_fat_cats() -> None: + """ + Create a Fat Cat + """ + pass + + +@router.get('/cats/{cat_id}', response_model=FatCats, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> FatCats: + """ + Info For a Specific Cat + """ + pass +``` + +`app/routers/slim_dogs.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from fastapi import APIRouter, FastAPI + +from ..dependencies import * + +router = APIRouter(tags=['Slim Dogs']) + + +@router.get('/dogs', response_model=SlimDogs, tags=['Slim Dogs']) +def list_slim_dogs(limit: Optional[int] = None) -> SlimDogs: + """ + List All Slim Dogs + """ + pass + + +@router.post('/dogs', response_model=None, tags=['Slim Dogs']) +def create_slim_dogs() -> None: + """ + Create a Slim Dog + """ + pass + + +@router.get('/dogs/{dog_id}', response_model=SlimDogs, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> SlimDogs: + """ + Info For a Specific Dog + """ + pass +``` + +`app/dependencies.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from typing import Optional + +from fastapi import Path + +from .models import FatCats, SlimDogs +``` ## PyPi [https://pypi.org/project/fastapi-code-generator](https://pypi.org/project/fastapi-code-generator) diff --git a/swagger.yaml b/swagger.yaml new file mode 100644 index 0000000..956a145 --- /dev/null +++ b/swagger.yaml @@ -0,0 +1,129 @@ + +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /cats: + get: + summary: List All Fat Cats + operationId: listFatCats + tags: + - Fat Cats + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of fat cats + content: + application/json: + schema: + $ref: "#/components/schemas/FatCats" + post: + summary: Create a Fat Cat + operationId: createFatCats + tags: + - Fat Cats + responses: + '201': + description: Null response + /cats/{catId}: + get: + summary: Info For a Specific Cat + operationId: showCatById + tags: + - Fat Cats + parameters: + - name: catId + in: path + required: true + description: The id of the cat to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/FatCats" + /dogs: + get: + summary: List All Slim Dogs + operationId: listSlimDogs + tags: + - Slim Dogs + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of slim dogs + content: + application/json: + schema: + $ref: "#/components/schemas/SlimDogs" + post: + summary: Create a Slim Dog + operationId: createSlimDogs + tags: + - Slim Dogs + responses: + '201': + description: Null response + /dogs/{dogId}: + get: + summary: Info For a Specific Dog + operationId: showDogById + tags: + - Slim Dogs + parameters: + - name: dogId + in: path + required: true + description: The id of the dog to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/SlimDogs" +components: + schemas: + Pet: + required: + - id + - name + properties: + id: + type: integer + name: + type: string + tag: + type: string + FatCats: + type: array + description: list of fat cats + items: + $ref: "#/components/schemas/Pet" + SlimDogs: + type: array + description: list of slim dogs + items: + $ref: "#/components/schemas/Pet" \ No newline at end of file From e3a674e8df25c74662e394ebc7d4e7021f099313 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Tue, 4 Apr 2023 18:11:48 +0300 Subject: [PATCH 11/20] README.md documentation edited --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 2ba384b..9126a34 100644 --- a/README.md +++ b/README.md @@ -427,8 +427,8 @@ visit: Visitor = custom_visitor │ ├── models.py # "models" of the application │ ├── dependencies.py # "dependencies" module, e.g. import app.dependencies │ └── routers # "routers" is a "app subpackage" -│ │ ├── fat_cats.py # "cats" submodule, e.g. import app.routers.fat_cats -│ │ └── slim_dogs.py # "dogs" submodule, e.g. import app.routers.slim_dogs +│ ├── fat_cats.py # "fat_cats" submodule, e.g. import app.routers.fat_cats +│ └── slim_dogs.py # "slim_dogs" submodule, e.g. import app.routers.slim_dogs ``` **_Generate main aside with all of its routers_**: ```bash From 0af270b63b5bda28fd84ff4657be4f6eb8da2bc0 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Sun, 16 Apr 2023 20:18:31 +0300 Subject: [PATCH 12/20] test using_routers added --- fastapi_code_generator/__main__.py | 23 ++-- .../modular_template/routers.jinja2 | 1 - .../using_routers_example/dependencies.py | 11 ++ .../using_routers_example/main.py | 24 ++++ .../using_routers_example/models.py | 23 ++++ .../using_routers_example/routers/fat_cats.py | 35 +++++ .../routers/slim_dogs.py | 35 +++++ .../data/modular_template/dependencies.jinja2 | 1 + tests/data/modular_template/main.jinja2 | 22 +++ tests/data/modular_template/routers.jinja2 | 36 +++++ .../using_routers/using_routers_example.yaml | 129 ++++++++++++++++++ tests/test_generate.py | 33 +++++ 12 files changed, 361 insertions(+), 12 deletions(-) create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/main.py create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/models.py create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py create mode 100644 tests/data/modular_template/dependencies.jinja2 create mode 100644 tests/data/modular_template/main.jinja2 create mode 100644 tests/data/modular_template/routers.jinja2 create mode 100644 tests/data/openapi/using_routers/using_routers_example.yaml diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 7ef60df..15d690b 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -64,9 +64,9 @@ def main( model_path = Path(model_file).with_suffix('.py') else: model_path = MODEL_PATH - if generate_routers: - template_dir = BUILTIN_MODULAR_TEMPLATE_DIR - Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) + # if generate_routers: + # template_dir = BUILTIN_MODULAR_TEMPLATE_DIR + # Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) if enum_field_as_literal: return generate_code( @@ -119,6 +119,9 @@ def generate_code( model_path = MODEL_PATH if not output_dir.exists(): output_dir.mkdir(parents=True) + if generate_routers: + template_dir = BUILTIN_MODULAR_TEMPLATE_DIR + Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) if not template_dir: template_dir = BUILTIN_TEMPLATE_DIR if enum_field_as_literal: @@ -169,9 +172,9 @@ def generate_code( for tag in operation.tags: all_tags.append(tag) # Convert from Tag Names to router_names - set_of_tags = set(all_tags) - routers = [re.sub(TITLE_PATTERN, '_', each.strip()).lower() for each in set_of_tags] - template_vars = {**template_vars, "routers": routers, "tags": set_of_tags} + sorted_tags = sorted(set(all_tags)) + routers = sorted([re.sub(TITLE_PATTERN, '_', tag.strip()).lower() for tag in sorted_tags]) + template_vars = {**template_vars, "routers": routers, "tags": sorted_tags} for target in template_dir.rglob("*"): relative_path = target.relative_to(template_dir) @@ -180,16 +183,14 @@ def generate_code( results[relative_path] = code_formatter.format_code(result) if generate_routers: - tags = set_of_tags + tags = sorted_tags results.pop(PosixPath("routers.jinja2")) if generate_routers_for_tags_filter: - if not Path(output_dir.joinpath("main.py")).exists(): - tags = set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(",")) - else: + if Path(output_dir.joinpath("main.py")).exists(): with open(Path(output_dir.joinpath("main.py")), 'r') as file: content = file.read() if "app.include_router" in content: - tags = set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(",")) + tags = sorted(set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(","))) for target in BUILTIN_MODULAR_TEMPLATE_DIR.rglob("routers.*"): relative_path = target.relative_to(template_dir) diff --git a/fastapi_code_generator/modular_template/routers.jinja2 b/fastapi_code_generator/modular_template/routers.jinja2 index ad2eb40..0cec624 100644 --- a/fastapi_code_generator/modular_template/routers.jinja2 +++ b/fastapi_code_generator/modular_template/routers.jinja2 @@ -1,7 +1,6 @@ from __future__ import annotations from fastapi import APIRouter -from fastapi import FastAPI from ..dependencies import * diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py b/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py new file mode 100644 index 0000000..ed4d7e2 --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py @@ -0,0 +1,11 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import Optional + +from fastapi import Path + +from .models import FatCats, SlimDogs diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/main.py b/tests/data/expected/openapi/using_routers/using_routers_example/main.py new file mode 100644 index 0000000..9a10df7 --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/main.py @@ -0,0 +1,24 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import fat_cats, slim_dogs + +app = FastAPI( + version='1.0.0', + title='Swagger Petstore', + license={'name': 'MIT'}, + servers=[{'url': 'http://petstore.swagger.io/v1'}], +) + +app.include_router(fat_cats.router) +app.include_router(slim_dogs.router) + + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/models.py b/tests/data/expected/openapi/using_routers/using_routers_example/models.py new file mode 100644 index 0000000..73bf28b --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/models.py @@ -0,0 +1,23 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Pet(BaseModel): + id: int + name: str + tag: Optional[str] = None + + +class FatCats(BaseModel): + __root__: List[Pet] = Field(..., description='list of fat cats') + + +class SlimDogs(BaseModel): + __root__: List[Pet] = Field(..., description='list of slim dogs') diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py b/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py new file mode 100644 index 0000000..1e5326f --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Fat Cats']) + + +@router.get('/cats', response_model=FatCats, tags=['Fat Cats']) +def list_fat_cats(limit: Optional[int] = None) -> FatCats: + """ + List All Fat Cats + """ + pass + + +@router.post('/cats', response_model=None, tags=['Fat Cats']) +def create_fat_cats() -> None: + """ + Create a Fat Cat + """ + pass + + +@router.get('/cats/{cat_id}', response_model=FatCats, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> FatCats: + """ + Info For a Specific Cat + """ + pass diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py b/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py new file mode 100644 index 0000000..ac1475f --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Slim Dogs']) + + +@router.get('/dogs', response_model=SlimDogs, tags=['Slim Dogs']) +def list_slim_dogs(limit: Optional[int] = None) -> SlimDogs: + """ + List All Slim Dogs + """ + pass + + +@router.post('/dogs', response_model=None, tags=['Slim Dogs']) +def create_slim_dogs() -> None: + """ + Create a Slim Dog + """ + pass + + +@router.get('/dogs/{dog_id}', response_model=SlimDogs, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> SlimDogs: + """ + Info For a Specific Dog + """ + pass diff --git a/tests/data/modular_template/dependencies.jinja2 b/tests/data/modular_template/dependencies.jinja2 new file mode 100644 index 0000000..ef3149f --- /dev/null +++ b/tests/data/modular_template/dependencies.jinja2 @@ -0,0 +1 @@ +{{imports}} \ No newline at end of file diff --git a/tests/data/modular_template/main.jinja2 b/tests/data/modular_template/main.jinja2 new file mode 100644 index 0000000..8d6a33d --- /dev/null +++ b/tests/data/modular_template/main.jinja2 @@ -0,0 +1,22 @@ +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import {{ routers | join(", ") }} + +app = FastAPI( + {% if info %} + {% for key,value in info.items() %} + {% set info_value= value.__repr__() %} + {{ key }} = {{info_value}}, + {% endfor %} + {% endif %} + ) + +{% for router in routers -%} +app.include_router({{router}}.router) +{% endfor -%} + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/tests/data/modular_template/routers.jinja2 b/tests/data/modular_template/routers.jinja2 new file mode 100644 index 0000000..0cec624 --- /dev/null +++ b/tests/data/modular_template/routers.jinja2 @@ -0,0 +1,36 @@ +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter( + tags=['{{tag}}'] + ) + +{% for operation in operations %} +{% if operation.tags[0] == tag %} +@router.{{operation.type}}('{{operation.snake_case_path}}', response_model={{operation.response}} + {% if operation.additional_responses %} + , responses={ + {% for status_code, models in operation.additional_responses.items() %} + '{{ status_code }}': { + {% for key, model in models.items() %} + '{{ key }}': {{ model }}{% if not loop.last %},{% endif %} + {% endfor %} + }{% if not loop.last %},{% endif %} + {% endfor %} + } + {% endif %} + {% if operation.tags%} + , tags={{operation.tags}} + {% endif %}) +def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operation.return_type}}: + {%- if operation.summary %} + """ + {{ operation.summary }} + """ + {%- endif %} + pass +{% endif %} +{% endfor %} \ No newline at end of file diff --git a/tests/data/openapi/using_routers/using_routers_example.yaml b/tests/data/openapi/using_routers/using_routers_example.yaml new file mode 100644 index 0000000..956a145 --- /dev/null +++ b/tests/data/openapi/using_routers/using_routers_example.yaml @@ -0,0 +1,129 @@ + +openapi: "3.0.0" +info: + version: 1.0.0 + title: Swagger Petstore + license: + name: MIT +servers: + - url: http://petstore.swagger.io/v1 +paths: + /cats: + get: + summary: List All Fat Cats + operationId: listFatCats + tags: + - Fat Cats + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of fat cats + content: + application/json: + schema: + $ref: "#/components/schemas/FatCats" + post: + summary: Create a Fat Cat + operationId: createFatCats + tags: + - Fat Cats + responses: + '201': + description: Null response + /cats/{catId}: + get: + summary: Info For a Specific Cat + operationId: showCatById + tags: + - Fat Cats + parameters: + - name: catId + in: path + required: true + description: The id of the cat to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/FatCats" + /dogs: + get: + summary: List All Slim Dogs + operationId: listSlimDogs + tags: + - Slim Dogs + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of slim dogs + content: + application/json: + schema: + $ref: "#/components/schemas/SlimDogs" + post: + summary: Create a Slim Dog + operationId: createSlimDogs + tags: + - Slim Dogs + responses: + '201': + description: Null response + /dogs/{dogId}: + get: + summary: Info For a Specific Dog + operationId: showDogById + tags: + - Slim Dogs + parameters: + - name: dogId + in: path + required: true + description: The id of the dog to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/SlimDogs" +components: + schemas: + Pet: + required: + - id + - name + properties: + id: + type: integer + name: + type: string + tag: + type: string + FatCats: + type: array + description: list of fat cats + items: + $ref: "#/components/schemas/Pet" + SlimDogs: + type: array + description: list of slim dogs + items: + $ref: "#/components/schemas/Pet" \ No newline at end of file diff --git a/tests/test_generate.py b/tests/test_generate.py index 507d74b..0be4719 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -11,11 +11,15 @@ OPEN_API_SECURITY_TEMPLATE_DIR_NAME = Path('openapi') / 'custom_template_security' OPEN_API_REMOTE_REF_DIR_NAME = Path('openapi') / 'remote_ref' OPEN_API_DISABLE_TIMESTAMP_DIR_NAME = Path('openapi') / 'disable_timestamp' +OPEN_API_USING_ROUTERS_DIR_NAME = Path('openapi') / 'using_routers' DATA_DIR = Path(__file__).parent / 'data' EXPECTED_DIR = DATA_DIR / 'expected' +BUILTIN_MODULAR_TEMPLATE_DIR = DATA_DIR / 'modular_template' + + @pytest.mark.parametrize( "oas_file", (DATA_DIR / OPEN_API_DEFAULT_TEMPLATE_DIR_NAME).glob("*.yaml") @@ -111,3 +115,32 @@ def test_disable_timestamp(oas_file): assert [f.name for f in output_files] == [f.name for f in expected_files] for output_file, expected_file in zip(output_files, expected_files): assert output_file.read_text() == expected_file.read_text() + + +@pytest.mark.parametrize( + "oas_file", (DATA_DIR / OPEN_API_USING_ROUTERS_DIR_NAME).glob("*.yaml") +) +@freeze_time("2023-04-11") +def test_generate_using_routers(oas_file): + with TemporaryDirectory() as tmp_dir: + output_dir = Path(tmp_dir) / oas_file.stem + Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) + generate_code( + input_name=oas_file.name, + input_text=oas_file.read_text(), + output_dir=output_dir, + template_dir=BUILTIN_MODULAR_TEMPLATE_DIR, + generate_routers=True, + ) + expected_dir = EXPECTED_DIR / OPEN_API_USING_ROUTERS_DIR_NAME / oas_file.stem + output_files = sorted(list(output_dir.glob('*'))) + expected_files = sorted(list(expected_dir.glob('*'))) + assert [f.name for f in output_files] == [f.name for f in expected_files] + for output_file, expected_file in zip(output_files, expected_files): + if output_file.is_dir() and expected_file.is_dir(): + output_inners = sorted(list((output_dir / output_file).glob('*'))) + expected_inners = sorted(list((expected_dir / expected_file).glob('*'))) + for output_inner, expected_inner in zip(output_inners, expected_inners): + assert output_inner.read_text() == expected_inner.read_text() + else: + assert output_file.read_text() == expected_file.read_text() From 1ab325c877adc757ef3c944e58faae3609d096bb Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 17 Apr 2023 15:09:50 +0300 Subject: [PATCH 13/20] test using_routers and specify tags added --- README.md | 133 ++++++++++++++++-- fastapi_code_generator/__main__.py | 14 +- swagger.yaml | 59 +++++++- .../using_routers_example/dependencies.py | 11 ++ .../expected/using_routers_example/main.py | 29 ++++ .../expected/using_routers_example/models.py | 27 ++++ .../using_routers_example/routers/fat_cats.py | 35 +++++ .../routers/slim_dogs.py | 35 +++++ .../routers/wild_boars.py | 35 +++++ .../using_routers_example/dependencies.py | 11 ++ .../modified/using_routers_example/main.py | 29 ++++ .../modified/using_routers_example/models.py | 27 ++++ .../using_routers_example/routers/fat_cats.py | 35 +++++ .../routers/slim_dogs.py | 35 +++++ .../routers/wild_boars.py | 35 +++++ .../using_routers_example/dependencies.py | 2 +- .../using_routers_example/main.py | 9 +- .../using_routers_example/models.py | 4 + .../using_routers_example/routers/fat_cats.py | 4 +- .../routers/slim_dogs.py | 4 +- .../routers/wild_boars.py | 35 +++++ .../using_routers/using_routers_example.yaml | 59 +++++++- tests/test_generate.py | 31 ++++ 23 files changed, 668 insertions(+), 30 deletions(-) create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/dependencies.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/main.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/models.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/fat_cats.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/slim_dogs.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/wild_boars.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/dependencies.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/main.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/models.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/fat_cats.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/slim_dogs.py create mode 100644 tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/wild_boars.py create mode 100644 tests/data/expected/openapi/using_routers/using_routers_example/routers/wild_boars.py diff --git a/README.md b/README.md index 9126a34..47b40d9 100644 --- a/README.md +++ b/README.md @@ -421,6 +421,7 @@ visit: Visitor = custom_visitor ``` ### Multiple Files using APIRouter (For Bigger Applications) + ``` ├── app # "app" is a Root directory │ ├── main.py # "main" module @@ -430,6 +431,9 @@ visit: Visitor = custom_visitor │ ├── fat_cats.py # "fat_cats" submodule, e.g. import app.routers.fat_cats │ └── slim_dogs.py # "slim_dogs" submodule, e.g. import app.routers.slim_dogs ``` + +See [documentation](https://fastapi.tiangolo.com/tutorial/bigger-applications/) of APIRouter OpenAPI for more details. + **_Generate main aside with all of its routers_**: ```bash $ fastapi-codegen --input swagger.yaml --output app --generate-routers @@ -437,7 +441,7 @@ $ fastapi-codegen --input swagger.yaml --output app --generate-routers **_Regenerate specific routers_**: ```bash -$ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify-tags "Slim Dogs, Fat Cats" +$ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify-tags "Wild Boars, Fat Cats" ``` @@ -445,6 +449,7 @@ $ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify swagger.yaml
 
+
 openapi: "3.0.0"
 info:
   version: 1.0.0
@@ -452,8 +457,58 @@ info:
   license:
     name: MIT
 servers:
+  - url: /
   - url: http://petstore.swagger.io/v1
+  - url: http://localhost:8080/
 paths:
+  /boars:
+    get:
+      summary: List All Wild Boars
+      operationId: listWildBoars
+      tags:
+        - Wild Boars
+      parameters:
+        - name: limit
+          in: query
+          description: How many items to return at one time (max 100)
+          required: false
+          schema:
+            type: integer
+      responses:
+        '200':
+          description: An array of wild boars
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/WildBoars"
+    post:
+      summary: Create a Wild Boar
+      operationId: createWildBoars
+      tags:
+        - Wild Boars
+      responses:
+        '201':
+          description: Null response
+  /boars/{boarId}:
+    get:
+      summary: Info For a Specific Boar
+      operationId: showBoarById
+      tags:
+        - Wild Boars
+      parameters:
+        - name: boarId
+          in: path
+          required: true
+          description: The id of the boar to retrieve
+          schema:
+            type: string
+      responses:
+        '200':
+          description: Expected response to a valid request
+          content:
+            application/json:
+              schema:
+                $ref: "#/components/schemas/Pet"
   /cats:
     get:
       summary: List All Fat Cats
@@ -501,7 +556,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/components/schemas/FatCats"
+                $ref: "#/components/schemas/Pet"
   /dogs:
     get:
       summary: List All Slim Dogs
@@ -549,7 +604,7 @@ paths:
           content:
             application/json:
               schema:
-                $ref: "#/components/schemas/SlimDogs"
+                $ref: "#/components/schemas/Pet"
 components:
   schemas:
     Pet:
@@ -573,6 +628,11 @@ components:
       description: list of slim dogs
       items:
         $ref: "#/components/schemas/Pet"
+    WildBoars:
+      type: array
+      description: list of wild boars
+      items:
+        $ref: "#/components/schemas/Pet"
 
 
@@ -588,17 +648,22 @@ from __future__ import annotations from fastapi import FastAPI -from .routers import fat_cats, slim_dogs +from .routers import fat_cats, slim_dogs, wild_boars app = FastAPI( version='1.0.0', title='Swagger Petstore', license={'name': 'MIT'}, - servers=[{'url': 'http://petstore.swagger.io/v1'}], + servers=[ + {'url': '/'}, + {'url': 'http://petstore.swagger.io/v1'}, + {'url': 'http://localhost:8080/'}, + ], ) app.include_router(fat_cats.router) app.include_router(slim_dogs.router) +app.include_router(wild_boars.router) @app.get("/") @@ -632,6 +697,10 @@ class FatCats(BaseModel): class SlimDogs(BaseModel): __root__: List[Pet] = Field(..., description='list of slim dogs') + + +class WildBoars(BaseModel): + __root__: List[Pet] = Field(..., description='list of wild boars') ``` `app/routers/fat_cats.py`: @@ -643,7 +712,7 @@ class SlimDogs(BaseModel): from __future__ import annotations -from fastapi import APIRouter, FastAPI +from fastapi import APIRouter from ..dependencies import * @@ -666,8 +735,8 @@ def create_fat_cats() -> None: pass -@router.get('/cats/{cat_id}', response_model=FatCats, tags=['Fat Cats']) -def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> FatCats: +@router.get('/cats/{cat_id}', response_model=Pet, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> Pet: """ Info For a Specific Cat """ @@ -683,7 +752,7 @@ def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> FatCats: from __future__ import annotations -from fastapi import APIRouter, FastAPI +from fastapi import APIRouter from ..dependencies import * @@ -706,14 +775,54 @@ def create_slim_dogs() -> None: pass -@router.get('/dogs/{dog_id}', response_model=SlimDogs, tags=['Slim Dogs']) -def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> SlimDogs: +@router.get('/dogs/{dog_id}', response_model=Pet, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> Pet: """ Info For a Specific Dog """ pass ``` +`app/routers/wild_boars.py`: + +```python +# generated by fastapi-codegen: +# filename: swagger.yaml +# timestamp: 2023-04-04T12:06:16+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Wild Boars']) + + +@router.get('/boars', response_model=WildBoars, tags=['Wild Boars']) +def list_wild_boars(limit: Optional[int] = None) -> WildBoars: + """ + List All Wild Boars + """ + pass + + +@router.post('/boars', response_model=None, tags=['Wild Boars']) +def create_wild_boars() -> None: + """ + Create a Wild Boar + """ + pass + + +@router.get('/boars/{boar_id}', response_model=Pet, tags=['Wild Boars']) +def show_boar_by_id(boar_id: str = Path(..., alias='boarId')) -> Pet: + """ + Info For a Specific Boar + """ + pass +``` + `app/dependencies.py`: ```python @@ -727,7 +836,7 @@ from typing import Optional from fastapi import Path -from .models import FatCats, SlimDogs +from .models import FatCats, Pet, SlimDogs, WildBoars ``` ## PyPi diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py index 15d690b..77ae0a9 100644 --- a/fastapi_code_generator/__main__.py +++ b/fastapi_code_generator/__main__.py @@ -50,8 +50,8 @@ def main( None, "--enum-field-as-literal" ), generate_routers: bool = typer.Option(False, "--generate-routers", "-r"), - generate_routers_for_tags_filter: Optional[str] = typer.Option( - None, "--generate-routers-for-tags-filter" + specify_tags: Optional[str] = typer.Option( + None, "--specify-tags" ), custom_visitors: Optional[List[Path]] = typer.Option( None, "--custom-visitor", "-c" @@ -78,7 +78,7 @@ def main( enum_field_as_literal, disable_timestamp=disable_timestamp, generate_routers=generate_routers, - generate_routers_for_tags_filter=generate_routers_for_tags_filter, + specify_tags=specify_tags, ) return generate_code( input_name, @@ -89,7 +89,7 @@ def main( custom_visitors=custom_visitors, disable_timestamp=disable_timestamp, generate_routers=generate_routers, - generate_routers_for_tags_filter=generate_routers_for_tags_filter, + specify_tags=specify_tags, ) @@ -113,7 +113,7 @@ def generate_code( custom_visitors: Optional[List[Path]] = [], disable_timestamp: bool = False, generate_routers: Optional[bool] = None, - generate_routers_for_tags_filter: Optional[str] = None + specify_tags: Optional[str] = None ) -> None: if not model_path: model_path = MODEL_PATH @@ -185,12 +185,12 @@ def generate_code( if generate_routers: tags = sorted_tags results.pop(PosixPath("routers.jinja2")) - if generate_routers_for_tags_filter: + if specify_tags: if Path(output_dir.joinpath("main.py")).exists(): with open(Path(output_dir.joinpath("main.py")), 'r') as file: content = file.read() if "app.include_router" in content: - tags = sorted(set(tag.strip() for tag in str(generate_routers_for_tags_filter).split(","))) + tags = sorted(set(tag.strip() for tag in str(specify_tags).split(","))) for target in BUILTIN_MODULAR_TEMPLATE_DIR.rglob("routers.*"): relative_path = target.relative_to(template_dir) diff --git a/swagger.yaml b/swagger.yaml index 956a145..8b12cb7 100644 --- a/swagger.yaml +++ b/swagger.yaml @@ -6,8 +6,58 @@ info: license: name: MIT servers: + - url: / - url: http://petstore.swagger.io/v1 + - url: http://localhost:8080/ paths: + /boars: + get: + summary: List All Wild Boars + operationId: listWildBoars + tags: + - Wild Boars + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of wild boars + content: + application/json: + schema: + $ref: "#/components/schemas/WildBoars" + post: + summary: Create a Wild Boar + operationId: createWildBoars + tags: + - Wild Boars + responses: + '201': + description: Null response + /boars/{boarId}: + get: + summary: Info For a Specific Boar + operationId: showBoarById + tags: + - Wild Boars + parameters: + - name: boarId + in: path + required: true + description: The id of the boar to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" /cats: get: summary: List All Fat Cats @@ -55,7 +105,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/FatCats" + $ref: "#/components/schemas/Pet" /dogs: get: summary: List All Slim Dogs @@ -103,7 +153,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/SlimDogs" + $ref: "#/components/schemas/Pet" components: schemas: Pet: @@ -125,5 +175,10 @@ components: SlimDogs: type: array description: list of slim dogs + items: + $ref: "#/components/schemas/Pet" + WildBoars: + type: array + description: list of wild boars items: $ref: "#/components/schemas/Pet" \ No newline at end of file diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/dependencies.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/dependencies.py new file mode 100644 index 0000000..ede6084 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/dependencies.py @@ -0,0 +1,11 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import Optional + +from fastapi import Path + +from .models import FatCats, Pet, SlimDogs, WildBoars diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/main.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/main.py new file mode 100644 index 0000000..b6de4f4 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/main.py @@ -0,0 +1,29 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import fat_cats, slim_dogs, wild_boars + +app = FastAPI( + version='1.0.0', + title='Swagger Petstore', + license={'name': 'MIT'}, + servers=[ + {'url': '/'}, + {'url': 'http://petstore.swagger.io/v1'}, + {'url': 'http://localhost:8080/'}, + ], +) + +app.include_router(fat_cats.router) +app.include_router(slim_dogs.router) +app.include_router(wild_boars.router) + + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/models.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/models.py new file mode 100644 index 0000000..ceb4515 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/models.py @@ -0,0 +1,27 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Pet(BaseModel): + id: int + name: str + tag: Optional[str] = None + + +class FatCats(BaseModel): + __root__: List[Pet] = Field(..., description='list of fat cats') + + +class SlimDogs(BaseModel): + __root__: List[Pet] = Field(..., description='list of slim dogs') + + +class WildBoars(BaseModel): + __root__: List[Pet] = Field(..., description='list of wild boars') diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/fat_cats.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/fat_cats.py new file mode 100644 index 0000000..77a7da4 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/fat_cats.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Fat Cats']) + + +@router.get('/cats', response_model=FatCats, tags=['Fat Cats']) +def list_fat_cats(limit: Optional[int] = None) -> FatCats: + """ + List All Fat Cats + """ + pass + + +@router.post('/cats', response_model=None, tags=['Fat Cats']) +def create_fat_cats() -> None: + """ + Create a Fat Cat + """ + pass + + +@router.get('/cats/{cat_id}', response_model=Pet, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> Pet: + """ + Info For a Specific Cat + """ + pass diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/slim_dogs.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/slim_dogs.py new file mode 100644 index 0000000..170237f --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/slim_dogs.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Slim Dogs']) + + +@router.get('/dogs', response_model=SlimDogs, tags=['Slim Dogs']) +def list_slim_dogs(limit: Optional[int] = None) -> SlimDogs: + """ + List All Slim Dogs + """ + return SlimDogs.parse_obj([{"id": "9", "name": "Pluto"}]) + + +@router.post('/dogs', response_model=None, tags=['Slim Dogs']) +def create_slim_dogs() -> None: + """ + Create a Slim Dog + """ + return None + + +@router.get('/dogs/{dog_id}', response_model=Pet, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> Pet: + """ + Info For a Specific Dog + """ + return Pet.parse_obj({"id": dog_id, "name": "Pluto"}) \ No newline at end of file diff --git a/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/wild_boars.py b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/wild_boars.py new file mode 100644 index 0000000..b0a849e --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/expected/using_routers_example/routers/wild_boars.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Wild Boars']) + + +@router.get('/boars', response_model=WildBoars, tags=['Wild Boars']) +def list_wild_boars(limit: Optional[int] = None) -> WildBoars: + """ + List All Wild Boars + """ + pass + + +@router.post('/boars', response_model=None, tags=['Wild Boars']) +def create_wild_boars() -> None: + """ + Create a Wild Boar + """ + pass + + +@router.get('/boars/{boar_id}', response_model=Pet, tags=['Wild Boars']) +def show_boar_by_id(boar_id: str = Path(..., alias='boarId')) -> Pet: + """ + Info For a Specific Boar + """ + pass diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/dependencies.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/dependencies.py new file mode 100644 index 0000000..ede6084 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/dependencies.py @@ -0,0 +1,11 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import Optional + +from fastapi import Path + +from .models import FatCats, Pet, SlimDogs, WildBoars diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/main.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/main.py new file mode 100644 index 0000000..b6de4f4 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/main.py @@ -0,0 +1,29 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import FastAPI + +from .routers import fat_cats, slim_dogs, wild_boars + +app = FastAPI( + version='1.0.0', + title='Swagger Petstore', + license={'name': 'MIT'}, + servers=[ + {'url': '/'}, + {'url': 'http://petstore.swagger.io/v1'}, + {'url': 'http://localhost:8080/'}, + ], +) + +app.include_router(fat_cats.router) +app.include_router(slim_dogs.router) +app.include_router(wild_boars.router) + + +@app.get("/") +async def root(): + return {"message": "Gateway of the App"} diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/models.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/models.py new file mode 100644 index 0000000..ceb4515 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/models.py @@ -0,0 +1,27 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from typing import List, Optional + +from pydantic import BaseModel, Field + + +class Pet(BaseModel): + id: int + name: str + tag: Optional[str] = None + + +class FatCats(BaseModel): + __root__: List[Pet] = Field(..., description='list of fat cats') + + +class SlimDogs(BaseModel): + __root__: List[Pet] = Field(..., description='list of slim dogs') + + +class WildBoars(BaseModel): + __root__: List[Pet] = Field(..., description='list of wild boars') diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/fat_cats.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/fat_cats.py new file mode 100644 index 0000000..77a7da4 --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/fat_cats.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Fat Cats']) + + +@router.get('/cats', response_model=FatCats, tags=['Fat Cats']) +def list_fat_cats(limit: Optional[int] = None) -> FatCats: + """ + List All Fat Cats + """ + pass + + +@router.post('/cats', response_model=None, tags=['Fat Cats']) +def create_fat_cats() -> None: + """ + Create a Fat Cat + """ + pass + + +@router.get('/cats/{cat_id}', response_model=Pet, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> Pet: + """ + Info For a Specific Cat + """ + pass diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/slim_dogs.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/slim_dogs.py new file mode 100644 index 0000000..170237f --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/slim_dogs.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Slim Dogs']) + + +@router.get('/dogs', response_model=SlimDogs, tags=['Slim Dogs']) +def list_slim_dogs(limit: Optional[int] = None) -> SlimDogs: + """ + List All Slim Dogs + """ + return SlimDogs.parse_obj([{"id": "9", "name": "Pluto"}]) + + +@router.post('/dogs', response_model=None, tags=['Slim Dogs']) +def create_slim_dogs() -> None: + """ + Create a Slim Dog + """ + return None + + +@router.get('/dogs/{dog_id}', response_model=Pet, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> Pet: + """ + Info For a Specific Dog + """ + return Pet.parse_obj({"id": dog_id, "name": "Pluto"}) \ No newline at end of file diff --git a/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/wild_boars.py b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/wild_boars.py new file mode 100644 index 0000000..b0a849e --- /dev/null +++ b/tests/data/expected/openapi/modify_specific_routers/modified/using_routers_example/routers/wild_boars.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Wild Boars']) + + +@router.get('/boars', response_model=WildBoars, tags=['Wild Boars']) +def list_wild_boars(limit: Optional[int] = None) -> WildBoars: + """ + List All Wild Boars + """ + pass + + +@router.post('/boars', response_model=None, tags=['Wild Boars']) +def create_wild_boars() -> None: + """ + Create a Wild Boar + """ + pass + + +@router.get('/boars/{boar_id}', response_model=Pet, tags=['Wild Boars']) +def show_boar_by_id(boar_id: str = Path(..., alias='boarId')) -> Pet: + """ + Info For a Specific Boar + """ + pass diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py b/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py index ed4d7e2..ede6084 100644 --- a/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py +++ b/tests/data/expected/openapi/using_routers/using_routers_example/dependencies.py @@ -8,4 +8,4 @@ from fastapi import Path -from .models import FatCats, SlimDogs +from .models import FatCats, Pet, SlimDogs, WildBoars diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/main.py b/tests/data/expected/openapi/using_routers/using_routers_example/main.py index 9a10df7..b6de4f4 100644 --- a/tests/data/expected/openapi/using_routers/using_routers_example/main.py +++ b/tests/data/expected/openapi/using_routers/using_routers_example/main.py @@ -6,17 +6,22 @@ from fastapi import FastAPI -from .routers import fat_cats, slim_dogs +from .routers import fat_cats, slim_dogs, wild_boars app = FastAPI( version='1.0.0', title='Swagger Petstore', license={'name': 'MIT'}, - servers=[{'url': 'http://petstore.swagger.io/v1'}], + servers=[ + {'url': '/'}, + {'url': 'http://petstore.swagger.io/v1'}, + {'url': 'http://localhost:8080/'}, + ], ) app.include_router(fat_cats.router) app.include_router(slim_dogs.router) +app.include_router(wild_boars.router) @app.get("/") diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/models.py b/tests/data/expected/openapi/using_routers/using_routers_example/models.py index 73bf28b..ceb4515 100644 --- a/tests/data/expected/openapi/using_routers/using_routers_example/models.py +++ b/tests/data/expected/openapi/using_routers/using_routers_example/models.py @@ -21,3 +21,7 @@ class FatCats(BaseModel): class SlimDogs(BaseModel): __root__: List[Pet] = Field(..., description='list of slim dogs') + + +class WildBoars(BaseModel): + __root__: List[Pet] = Field(..., description='list of wild boars') diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py b/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py index 1e5326f..77a7da4 100644 --- a/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py +++ b/tests/data/expected/openapi/using_routers/using_routers_example/routers/fat_cats.py @@ -27,8 +27,8 @@ def create_fat_cats() -> None: pass -@router.get('/cats/{cat_id}', response_model=FatCats, tags=['Fat Cats']) -def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> FatCats: +@router.get('/cats/{cat_id}', response_model=Pet, tags=['Fat Cats']) +def show_cat_by_id(cat_id: str = Path(..., alias='catId')) -> Pet: """ Info For a Specific Cat """ diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py b/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py index ac1475f..776c622 100644 --- a/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py +++ b/tests/data/expected/openapi/using_routers/using_routers_example/routers/slim_dogs.py @@ -27,8 +27,8 @@ def create_slim_dogs() -> None: pass -@router.get('/dogs/{dog_id}', response_model=SlimDogs, tags=['Slim Dogs']) -def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> SlimDogs: +@router.get('/dogs/{dog_id}', response_model=Pet, tags=['Slim Dogs']) +def show_dog_by_id(dog_id: str = Path(..., alias='dogId')) -> Pet: """ Info For a Specific Dog """ diff --git a/tests/data/expected/openapi/using_routers/using_routers_example/routers/wild_boars.py b/tests/data/expected/openapi/using_routers/using_routers_example/routers/wild_boars.py new file mode 100644 index 0000000..b0a849e --- /dev/null +++ b/tests/data/expected/openapi/using_routers/using_routers_example/routers/wild_boars.py @@ -0,0 +1,35 @@ +# generated by fastapi-codegen: +# filename: using_routers_example.yaml +# timestamp: 2023-04-11T00:00:00+00:00 + +from __future__ import annotations + +from fastapi import APIRouter + +from ..dependencies import * + +router = APIRouter(tags=['Wild Boars']) + + +@router.get('/boars', response_model=WildBoars, tags=['Wild Boars']) +def list_wild_boars(limit: Optional[int] = None) -> WildBoars: + """ + List All Wild Boars + """ + pass + + +@router.post('/boars', response_model=None, tags=['Wild Boars']) +def create_wild_boars() -> None: + """ + Create a Wild Boar + """ + pass + + +@router.get('/boars/{boar_id}', response_model=Pet, tags=['Wild Boars']) +def show_boar_by_id(boar_id: str = Path(..., alias='boarId')) -> Pet: + """ + Info For a Specific Boar + """ + pass diff --git a/tests/data/openapi/using_routers/using_routers_example.yaml b/tests/data/openapi/using_routers/using_routers_example.yaml index 956a145..8b12cb7 100644 --- a/tests/data/openapi/using_routers/using_routers_example.yaml +++ b/tests/data/openapi/using_routers/using_routers_example.yaml @@ -6,8 +6,58 @@ info: license: name: MIT servers: + - url: / - url: http://petstore.swagger.io/v1 + - url: http://localhost:8080/ paths: + /boars: + get: + summary: List All Wild Boars + operationId: listWildBoars + tags: + - Wild Boars + parameters: + - name: limit + in: query + description: How many items to return at one time (max 100) + required: false + schema: + type: integer + responses: + '200': + description: An array of wild boars + content: + application/json: + schema: + $ref: "#/components/schemas/WildBoars" + post: + summary: Create a Wild Boar + operationId: createWildBoars + tags: + - Wild Boars + responses: + '201': + description: Null response + /boars/{boarId}: + get: + summary: Info For a Specific Boar + operationId: showBoarById + tags: + - Wild Boars + parameters: + - name: boarId + in: path + required: true + description: The id of the boar to retrieve + schema: + type: string + responses: + '200': + description: Expected response to a valid request + content: + application/json: + schema: + $ref: "#/components/schemas/Pet" /cats: get: summary: List All Fat Cats @@ -55,7 +105,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/FatCats" + $ref: "#/components/schemas/Pet" /dogs: get: summary: List All Slim Dogs @@ -103,7 +153,7 @@ paths: content: application/json: schema: - $ref: "#/components/schemas/SlimDogs" + $ref: "#/components/schemas/Pet" components: schemas: Pet: @@ -125,5 +175,10 @@ components: SlimDogs: type: array description: list of slim dogs + items: + $ref: "#/components/schemas/Pet" + WildBoars: + type: array + description: list of wild boars items: $ref: "#/components/schemas/Pet" \ No newline at end of file diff --git a/tests/test_generate.py b/tests/test_generate.py index 0be4719..c56105e 100644 --- a/tests/test_generate.py +++ b/tests/test_generate.py @@ -19,6 +19,7 @@ BUILTIN_MODULAR_TEMPLATE_DIR = DATA_DIR / 'modular_template' +SPECIFIC_TAGS = 'Wild Boars, Fat Cats' @pytest.mark.parametrize( @@ -144,3 +145,33 @@ def test_generate_using_routers(oas_file): assert output_inner.read_text() == expected_inner.read_text() else: assert output_file.read_text() == expected_file.read_text() + + +@pytest.mark.parametrize( + "oas_file", (DATA_DIR / OPEN_API_USING_ROUTERS_DIR_NAME).glob("*.yaml") +) +@freeze_time("2023-04-11") +def test_generate_modify_specific_routers(oas_file): + test_dir = EXPECTED_DIR / 'openapi/modify_specific_routers/modified' + output_dir = Path(test_dir) / oas_file.stem + Path(output_dir / "routers").mkdir(parents=True, exist_ok=True) + generate_code( + input_name=oas_file.name, + input_text=oas_file.read_text(), + output_dir=output_dir, + template_dir=BUILTIN_MODULAR_TEMPLATE_DIR, + generate_routers=True, + specify_tags=SPECIFIC_TAGS + ) + expected_dir = EXPECTED_DIR / 'openapi/modify_specific_routers/expected' / oas_file.stem + output_files = sorted(list(output_dir.glob('*'))) + expected_files = sorted(list(expected_dir.glob('*'))) + assert [f.name for f in output_files] == [f.name for f in expected_files] + for output_file, expected_file in zip(output_files, expected_files): + if output_file.is_dir() and expected_file.is_dir(): + output_inners = sorted(list((output_dir / output_file).glob('*'))) + expected_inners = sorted(list((expected_dir / expected_file).glob('*'))) + for output_inner, expected_inner in zip(output_inners, expected_inners): + assert output_inner.read_text() == expected_inner.read_text() + else: + assert output_file.read_text() == expected_file.read_text() From c61b1f86c998dfa51919b184820ee0499b9bf2a0 Mon Sep 17 00:00:00 2001 From: v1kAn0v Date: Mon, 17 Apr 2023 15:10:56 +0300 Subject: [PATCH 14/20] test using_routers and specify tags added --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 47b40d9..aa65945 100644 --- a/README.md +++ b/README.md @@ -449,7 +449,6 @@ $ fastapi-codegen --input swagger.yaml --output app --generate-routers --specify swagger.yaml
 
-
 openapi: "3.0.0"
 info:
   version: 1.0.0

From 062790aaebfb5b302d5d3515ce6e46dee880fd6e Mon Sep 17 00:00:00 2001
From: v1kAn0v 
Date: Mon, 17 Apr 2023 15:56:57 +0300
Subject: [PATCH 15/20] test using_routers and specify tags added

---
 README.md | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/README.md b/README.md
index aa65945..43c9359 100644
--- a/README.md
+++ b/README.md
@@ -314,7 +314,7 @@ def {{operation.function_name}}({{operation.snake_case_arguments}}) -> {{operati
 
 ```
 
-### modular_template
+### modular template
 `modular_template/main.jinja2`:
 ```jinja
 from __future__ import annotations
@@ -429,7 +429,8 @@ visit: Visitor = custom_visitor
 │   ├── dependencies.py      # "dependencies" module, e.g. import app.dependencies
 │   └── routers              # "routers" is a "app subpackage"
 │       ├── fat_cats.py      # "fat_cats" submodule, e.g. import app.routers.fat_cats
-│       └── slim_dogs.py     # "slim_dogs" submodule, e.g. import app.routers.slim_dogs
+│       ├── slim_dogs.py     # "slim_dogs" submodule, e.g. import app.routers.slim_dogs
+│       └── wild_boars.py    # "wild_boars" submodule, e.g. import app.routers.wild_boars
 ```
 
 See [documentation](https://fastapi.tiangolo.com/tutorial/bigger-applications/) of APIRouter OpenAPI for more details.

From 2e1817c951cbd18bcd1804593fcbac2b43ea8746 Mon Sep 17 00:00:00 2001
From: v1kAn0v 
Date: Mon, 17 Apr 2023 19:17:13 +0300
Subject: [PATCH 16/20] test using_routers and specify tags added

---
 fastapi_code_generator/__main__.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py
index 77ae0a9..adde643 100644
--- a/fastapi_code_generator/__main__.py
+++ b/fastapi_code_generator/__main__.py
@@ -167,7 +167,7 @@ def generate_code(
         template_vars = {**template_vars, **visitor_result}
 
     if generate_routers:
-        for operation in template_vars.get("operations"):
+        for operation in template_vars.get("operations", []):
             if hasattr(operation, "tags"):
                 for tag in operation.tags:
                     all_tags.append(tag)
@@ -194,7 +194,7 @@ def generate_code(
 
         for target in BUILTIN_MODULAR_TEMPLATE_DIR.rglob("routers.*"):
             relative_path = target.relative_to(template_dir)
-            for router, tag in zip(routers, template_vars["tags"]):
+            for router, tag in zip(routers, sorted_tags):
                 if not Path(output_dir.joinpath("routers", router)).with_suffix(".py").exists() or tag in tags:
                     template_vars["tag"] = tag.strip()
                     template = environment.get_template(str(relative_path))

From f011f87427ec9129bcda3091bb213c6966b4567d Mon Sep 17 00:00:00 2001
From: v1kAn0v 
Date: Tue, 18 Apr 2023 11:25:24 +0300
Subject: [PATCH 17/20] test using_routers and specify tags added

---
 fastapi_code_generator/__main__.py | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py
index adde643..fa9582c 100644
--- a/fastapi_code_generator/__main__.py
+++ b/fastapi_code_generator/__main__.py
@@ -167,7 +167,8 @@ def generate_code(
         template_vars = {**template_vars, **visitor_result}
 
     if generate_routers:
-        for operation in template_vars.get("operations", []):
+        operations: Any = template_vars.get("operations", [])
+        for operation in operations:
             if hasattr(operation, "tags"):
                 for tag in operation.tags:
                     all_tags.append(tag)

From 085018854326b043849df1b15ccaf846c860750e Mon Sep 17 00:00:00 2001
From: v1kan0v 
Date: Tue, 18 Apr 2023 11:31:14 +0000
Subject: [PATCH 18/20] cosmetics

---
 fastapi_code_generator/__main__.py | 24 ++++++++++++++++--------
 tests/test_generate.py             |  6 ++++--
 2 files changed, 20 insertions(+), 10 deletions(-)

diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py
index fa9582c..a8ef38b 100644
--- a/fastapi_code_generator/__main__.py
+++ b/fastapi_code_generator/__main__.py
@@ -1,8 +1,9 @@
+import re
 from datetime import datetime, timezone
 from importlib.util import module_from_spec, spec_from_file_location
 from pathlib import Path, PosixPath
 from typing import Any, Dict, List, Optional
-import re
+
 import typer
 from datamodel_code_generator import LiteralType, PythonVersion, chdir
 from datamodel_code_generator.format import CodeFormatter
@@ -50,9 +51,7 @@ def main(
         None, "--enum-field-as-literal"
     ),
     generate_routers: bool = typer.Option(False, "--generate-routers", "-r"),
-    specify_tags: Optional[str] = typer.Option(
-        None, "--specify-tags"
-    ),
+    specify_tags: Optional[str] = typer.Option(None, "--specify-tags"),
     custom_visitors: Optional[List[Path]] = typer.Option(
         None, "--custom-visitor", "-c"
     ),
@@ -113,7 +112,7 @@ def generate_code(
     custom_visitors: Optional[List[Path]] = [],
     disable_timestamp: bool = False,
     generate_routers: Optional[bool] = None,
-    specify_tags: Optional[str] = None
+    specify_tags: Optional[str] = None,
 ) -> None:
     if not model_path:
         model_path = MODEL_PATH
@@ -174,7 +173,9 @@ def generate_code(
                     all_tags.append(tag)
     # Convert from Tag Names to router_names
     sorted_tags = sorted(set(all_tags))
-    routers = sorted([re.sub(TITLE_PATTERN, '_', tag.strip()).lower() for tag in sorted_tags])
+    routers = sorted(
+        [re.sub(TITLE_PATTERN, '_', tag.strip()).lower() for tag in sorted_tags]
+    )
     template_vars = {**template_vars, "routers": routers, "tags": sorted_tags}
 
     for target in template_dir.rglob("*"):
@@ -191,12 +192,19 @@ def generate_code(
                 with open(Path(output_dir.joinpath("main.py")), 'r') as file:
                     content = file.read()
                     if "app.include_router" in content:
-                        tags = sorted(set(tag.strip() for tag in str(specify_tags).split(",")))
+                        tags = sorted(
+                            set(tag.strip() for tag in str(specify_tags).split(","))
+                        )
 
         for target in BUILTIN_MODULAR_TEMPLATE_DIR.rglob("routers.*"):
             relative_path = target.relative_to(template_dir)
             for router, tag in zip(routers, sorted_tags):
-                if not Path(output_dir.joinpath("routers", router)).with_suffix(".py").exists() or tag in tags:
+                if (
+                    not Path(output_dir.joinpath("routers", router))
+                    .with_suffix(".py")
+                    .exists()
+                    or tag in tags
+                ):
                     template_vars["tag"] = tag.strip()
                     template = environment.get_template(str(relative_path))
                     result = template.render(template_vars)
diff --git a/tests/test_generate.py b/tests/test_generate.py
index c56105e..095cf1c 100644
--- a/tests/test_generate.py
+++ b/tests/test_generate.py
@@ -161,9 +161,11 @@ def test_generate_modify_specific_routers(oas_file):
         output_dir=output_dir,
         template_dir=BUILTIN_MODULAR_TEMPLATE_DIR,
         generate_routers=True,
-        specify_tags=SPECIFIC_TAGS
+        specify_tags=SPECIFIC_TAGS,
+    )
+    expected_dir = (
+        EXPECTED_DIR / 'openapi/modify_specific_routers/expected' / oas_file.stem
     )
-    expected_dir = EXPECTED_DIR / 'openapi/modify_specific_routers/expected' / oas_file.stem
     output_files = sorted(list(output_dir.glob('*')))
     expected_files = sorted(list(expected_dir.glob('*')))
     assert [f.name for f in output_files] == [f.name for f in expected_files]

From c193387394e2d44cc4a0833c5b567cc180e2e9dc Mon Sep 17 00:00:00 2001
From: v1kan0v 
Date: Thu, 27 Apr 2023 05:58:50 +0000
Subject: [PATCH 19/20] change PosixPath to Path

---
 fastapi_code_generator/__main__.py | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py
index a8ef38b..6a41759 100644
--- a/fastapi_code_generator/__main__.py
+++ b/fastapi_code_generator/__main__.py
@@ -1,7 +1,7 @@
 import re
 from datetime import datetime, timezone
 from importlib.util import module_from_spec, spec_from_file_location
-from pathlib import Path, PosixPath
+from pathlib import Path
 from typing import Any, Dict, List, Optional
 
 import typer
@@ -186,7 +186,7 @@ def generate_code(
 
     if generate_routers:
         tags = sorted_tags
-        results.pop(PosixPath("routers.jinja2"))
+        results.pop(Path("routers.jinja2"))
         if specify_tags:
             if Path(output_dir.joinpath("main.py")).exists():
                 with open(Path(output_dir.joinpath("main.py")), 'r') as file:

From dfd448395bbb760eae1302f65c35ea421f86bb2d Mon Sep 17 00:00:00 2001
From: v1kan0v 
Date: Thu, 27 Apr 2023 14:48:31 +0000
Subject: [PATCH 20/20] remove commented lines

---
 fastapi_code_generator/__main__.py | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/fastapi_code_generator/__main__.py b/fastapi_code_generator/__main__.py
index 6a41759..9f214e8 100644
--- a/fastapi_code_generator/__main__.py
+++ b/fastapi_code_generator/__main__.py
@@ -63,9 +63,6 @@ def main(
         model_path = Path(model_file).with_suffix('.py')
     else:
         model_path = MODEL_PATH
-    # if generate_routers:
-    #     template_dir = BUILTIN_MODULAR_TEMPLATE_DIR
-    #     Path(output_dir / "routers").mkdir(parents=True, exist_ok=True)
 
     if enum_field_as_literal:
         return generate_code(