pyopenapi-gen 0.8.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyopenapi_gen-0.8.3/.bandit +1 -0
- pyopenapi_gen-0.8.3/.cursor/mcp.json +10 -0
- pyopenapi_gen-0.8.3/.cursor/rules/architecture.mdc +86 -0
- pyopenapi_gen-0.8.3/.cursor/rules/coding-conventions.mdc +190 -0
- pyopenapi_gen-0.8.3/.cursor/rules/project-goal.mdc +84 -0
- pyopenapi_gen-0.8.3/.cursor/rules/testing.mdc +185 -0
- pyopenapi_gen-0.8.3/.github/BRANCH_PROTECTION.md +126 -0
- pyopenapi_gen-0.8.3/.github/CODEOWNERS +30 -0
- pyopenapi_gen-0.8.3/.github/ISSUE_TEMPLATE/bug_report.md +50 -0
- pyopenapi_gen-0.8.3/.github/ISSUE_TEMPLATE/feature_request.md +31 -0
- pyopenapi_gen-0.8.3/.github/dependabot.yml +38 -0
- pyopenapi_gen-0.8.3/.github/workflows/ci.yml +44 -0
- pyopenapi_gen-0.8.3/.github/workflows/claude.yml +37 -0
- pyopenapi_gen-0.8.3/.github/workflows/main-checks.yml +98 -0
- pyopenapi_gen-0.8.3/.github/workflows/pr-checks.yml +142 -0
- pyopenapi_gen-0.8.3/.github/workflows/production-release.yml +170 -0
- pyopenapi_gen-0.8.3/.github/workflows/promote-to-staging.yml +65 -0
- pyopenapi_gen-0.8.3/.github/workflows/pypi-publish.yml +40 -0
- pyopenapi_gen-0.8.3/.github/workflows/staging-publish.yml +108 -0
- pyopenapi_gen-0.8.3/.github/workflows/testpypi-publish.yml +42 -0
- pyopenapi_gen-0.8.3/.gitignore +187 -0
- pyopenapi_gen-0.8.3/.vscode/settings.json +16 -0
- pyopenapi_gen-0.8.3/CLAUDE.md +635 -0
- pyopenapi_gen-0.8.3/LICENSE +21 -0
- pyopenapi_gen-0.8.3/Makefile +60 -0
- pyopenapi_gen-0.8.3/PKG-INFO +224 -0
- pyopenapi_gen-0.8.3/README.md +182 -0
- pyopenapi_gen-0.8.3/TEST_MAP.md +223 -0
- pyopenapi_gen-0.8.3/docs/architecture.md +163 -0
- pyopenapi_gen-0.8.3/docs/endpoint_visitor.md +12 -0
- pyopenapi_gen-0.8.3/docs/helpers.md +50 -0
- pyopenapi_gen-0.8.3/docs/ir_models.md +90 -0
- pyopenapi_gen-0.8.3/docs/line_writer.md +206 -0
- pyopenapi_gen-0.8.3/docs/loader.md +11 -0
- pyopenapi_gen-0.8.3/docs/model_visitor.md +12 -0
- pyopenapi_gen-0.8.3/docs/render_context.md +11 -0
- pyopenapi_gen-0.8.3/docs/unified_type_resolution.md +206 -0
- pyopenapi_gen-0.8.3/input/business_swagger.json +11723 -0
- pyopenapi_gen-0.8.3/input/minimal_swagger.json +49 -0
- pyopenapi_gen-0.8.3/input/minimal_syntax_test.json +120 -0
- pyopenapi_gen-0.8.3/input/test_name_collision_spec.json +121 -0
- pyopenapi_gen-0.8.3/mkdocs.yml +22 -0
- pyopenapi_gen-0.8.3/poetry.lock +2361 -0
- pyopenapi_gen-0.8.3/pyproject.toml +93 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/__init__.py +114 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/__main__.py +6 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/cli.py +86 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/context/file_manager.py +52 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/context/import_collector.py +382 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/context/render_context.py +630 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/__init__.py +0 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/auth/base.py +22 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/auth/plugins.py +89 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/exceptions.py +25 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/http_transport.py +219 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/__init__.py +12 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/loader.py +158 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/operations/__init__.py +12 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/operations/parser.py +155 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/operations/post_processor.py +60 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/operations/request_body.py +85 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/parameters/__init__.py +10 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/parameters/parser.py +121 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/responses/__init__.py +10 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/responses/parser.py +104 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/schemas/__init__.py +11 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/loader/schemas/extractor.py +184 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/pagination.py +64 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/__init__.py +13 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/__init__.py +9 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/__init__.py +0 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/cyclic_properties.py +66 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/direct_cycle.py +33 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/existing_schema.py +22 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/list_response.py +54 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py +52 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py +50 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py +51 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/ref_resolution/resolve_schema_ref.py +86 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/common/type_parser.py +74 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/context.py +184 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/cycle_helpers.py +123 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/all_of_parser.py +77 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/any_of_parser.py +79 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/array_items_parser.py +69 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/one_of_parser.py +72 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/keywords/properties_parser.py +98 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/schema_finalizer.py +166 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/schema_parser.py +610 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/transformers/__init__.py +0 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py +285 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/transformers/inline_object_promoter.py +117 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/parsing/unified_cycle_detection.py +293 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/postprocess_manager.py +161 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/schemas.py +40 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/streaming_helpers.py +86 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/telemetry.py +67 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/utils.py +409 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/warning_collector.py +83 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/writers/code_writer.py +135 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/writers/documentation_writer.py +222 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/writers/line_writer.py +217 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core/writers/python_construct_renderer.py +274 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/core_package_template/README.md +21 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emit/models_emitter.py +143 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/client_emitter.py +51 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/core_emitter.py +181 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/docs_emitter.py +44 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/endpoints_emitter.py +223 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/exceptions_emitter.py +52 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/emitters/models_emitter.py +428 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/generator/client_generator.py +562 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/endpoint_utils.py +552 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_cleaner.py +341 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_helper.py +112 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/array_resolver.py +57 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/composition_resolver.py +79 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/finalizer.py +89 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/named_resolver.py +174 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/object_resolver.py +212 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/primitive_resolver.py +57 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/type_resolution/resolver.py +48 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/helpers/url_utils.py +14 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/http_types.py +20 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/ir.py +167 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/py.typed +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/__init__.py +11 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/contracts/__init__.py +13 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/contracts/protocols.py +106 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/contracts/types.py +30 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/resolvers/__init__.py +7 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/resolvers/reference_resolver.py +71 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/resolvers/response_resolver.py +203 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/resolvers/schema_resolver.py +367 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/services/__init__.py +5 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/types/services/type_service.py +133 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/client_visitor.py +228 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/docs_visitor.py +38 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/endpoint_visitor.py +103 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/docstring_generator.py +121 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py +87 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/request_generator.py +103 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py +497 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/signature_generator.py +88 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/generators/url_args_generator.py +183 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/processors/__init__.py +1 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/processors/import_analyzer.py +76 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/endpoint/processors/parameter_processor.py +171 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/exception_visitor.py +52 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/model/__init__.py +0 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/model/alias_generator.py +89 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/model/dataclass_generator.py +197 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/model/enum_generator.py +200 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/model/model_visitor.py +197 -0
- pyopenapi_gen-0.8.3/src/pyopenapi_gen/visit/visitor.py +97 -0
- pyopenapi_gen-0.8.3/tests/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/auth/auth_analysis.md +22 -0
- pyopenapi_gen-0.8.3/tests/auth/test_auth_base.py +116 -0
- pyopenapi_gen-0.8.3/tests/auth/test_auth_plugins.py +133 -0
- pyopenapi_gen-0.8.3/tests/cli/cli_analysis.md +64 -0
- pyopenapi_gen-0.8.3/tests/cli/test_cli_backup_diff.py +60 -0
- pyopenapi_gen-0.8.3/tests/cli/test_cli_edge_cases.py +106 -0
- pyopenapi_gen-0.8.3/tests/cli/test_cli_edge_cases_comprehensive.py +647 -0
- pyopenapi_gen-0.8.3/tests/cli/test_cli_internal_utils.py +29 -0
- pyopenapi_gen-0.8.3/tests/cli/test_http_pagination_cli.py +188 -0
- pyopenapi_gen-0.8.3/tests/context/context_analysis.md +75 -0
- pyopenapi_gen-0.8.3/tests/context/test_file_manager.py +176 -0
- pyopenapi_gen-0.8.3/tests/context/test_import_collector.py +791 -0
- pyopenapi_gen-0.8.3/tests/context/test_render_context.py +446 -0
- pyopenapi_gen-0.8.3/tests/context/test_render_context_imports.py +38 -0
- pyopenapi_gen-0.8.3/tests/context/test_render_context_relative_paths.py +103 -0
- pyopenapi_gen-0.8.3/tests/core/core_analysis.md +341 -0
- pyopenapi_gen-0.8.3/tests/core/loader/test_extractor.py +900 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/helpers_analysis.md +196 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_cyclic_properties.py +132 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_direct_cycle.py +78 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_existing_schema.py +74 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_list_response.py +125 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_missing_ref.py +145 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_new_schema.py +142 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/common/ref_resolution/helpers/test_stripped_suffix.py +156 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/keywords_analysis.md +182 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/test_all_of_parser.py +641 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/test_any_of_parser.py +306 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/test_array_items_parser.py +197 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/test_one_of_parser.py +242 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/keywords/test_properties_parser.py +453 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/parsing_analysis.md +221 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_context.py +269 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_cycle_detection.py +662 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_cycle_helpers.py +195 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_improved_schema_naming.py +330 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_inline_enum_extractor.py +436 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_inline_object_promoter.py +160 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_logging.py +281 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_ref_resolver.py +150 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_schema_finalizer.py +283 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_schema_parser.py +852 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_schema_parser_list_response.py +202 -0
- pyopenapi_gen-0.8.3/tests/core/parsing/test_type_parser.py +216 -0
- pyopenapi_gen-0.8.3/tests/core/test_dataclass_serialization.py +351 -0
- pyopenapi_gen-0.8.3/tests/core/test_detect_circular_imports.py +99 -0
- pyopenapi_gen-0.8.3/tests/core/test_edge_cases_integration.py +757 -0
- pyopenapi_gen-0.8.3/tests/core/test_edge_cases_systematic.py +603 -0
- pyopenapi_gen-0.8.3/tests/core/test_exceptions_module.py +45 -0
- pyopenapi_gen-0.8.3/tests/core/test_forward_references.py +78 -0
- pyopenapi_gen-0.8.3/tests/core/test_http_transport.py +75 -0
- pyopenapi_gen-0.8.3/tests/core/test_import_resolution.py +63 -0
- pyopenapi_gen-0.8.3/tests/core/test_ir.py +153 -0
- pyopenapi_gen-0.8.3/tests/core/test_ir_schema.py +22 -0
- pyopenapi_gen-0.8.3/tests/core/test_loader.py +595 -0
- pyopenapi_gen-0.8.3/tests/core/test_loader_extensive.py +173 -0
- pyopenapi_gen-0.8.3/tests/core/test_loader_invalid_refs.py +105 -0
- pyopenapi_gen-0.8.3/tests/core/test_loader_malformed.py +24 -0
- pyopenapi_gen-0.8.3/tests/core/test_loader_media_types.py +65 -0
- pyopenapi_gen-0.8.3/tests/core/test_pagination.py +217 -0
- pyopenapi_gen-0.8.3/tests/core/test_parsing_context.py +22 -0
- pyopenapi_gen-0.8.3/tests/core/test_protocol_defaults.py +28 -0
- pyopenapi_gen-0.8.3/tests/core/test_schema_parser_specific_case.py +40 -0
- pyopenapi_gen-0.8.3/tests/core/test_schemas.py +203 -0
- pyopenapi_gen-0.8.3/tests/core/test_simple_self_ref_check.py +142 -0
- pyopenapi_gen-0.8.3/tests/core/test_streaming_helpers.py +154 -0
- pyopenapi_gen-0.8.3/tests/core/test_telemetry.py +60 -0
- pyopenapi_gen-0.8.3/tests/core/test_telemetry_client.py +66 -0
- pyopenapi_gen-0.8.3/tests/core/test_utils.py +359 -0
- pyopenapi_gen-0.8.3/tests/core/test_warning_collector.py +49 -0
- pyopenapi_gen-0.8.3/tests/core/writers/test_code_writer.py +98 -0
- pyopenapi_gen-0.8.3/tests/core/writers/test_documentation_writer.py +480 -0
- pyopenapi_gen-0.8.3/tests/core/writers/test_line_writer.py +600 -0
- pyopenapi_gen-0.8.3/tests/core/writers/writers_analysis.md +49 -0
- pyopenapi_gen-0.8.3/tests/emitters/emitters_analysis.md +162 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_client_emitter.py +62 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_docs_emitter.py +110 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_duplicate_operations.py +110 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_endpoints_emitter.py +881 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_exceptions_emitter.py +54 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_list_response_generation.py +163 -0
- pyopenapi_gen-0.8.3/tests/emitters/test_models_emitter.py +716 -0
- pyopenapi_gen-0.8.3/tests/end_to_end/test_dataclass_serialization_e2e.py +170 -0
- pyopenapi_gen-0.8.3/tests/examples/test_developer_experience_demo.py +221 -0
- pyopenapi_gen-0.8.3/tests/generation/generation_analysis.md +71 -0
- pyopenapi_gen-0.8.3/tests/generation/test_external_core_package.py +312 -0
- pyopenapi_gen-0.8.3/tests/generation/test_response_unwrapping.py +391 -0
- pyopenapi_gen-0.8.3/tests/generation_issues/specs/minimal_addmessage_like.json +112 -0
- pyopenapi_gen-0.8.3/tests/generation_issues/test_addmessage_like_issues.py +185 -0
- pyopenapi_gen-0.8.3/tests/generation_issues/test_agent_include_parameter_typing.py +126 -0
- pyopenapi_gen-0.8.3/tests/generation_issues/test_message_batch_response_issue.py +173 -0
- pyopenapi_gen-0.8.3/tests/helpers/helpers_analysis.md +247 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_array_resolver.py +189 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_endpoint_utils.py +722 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_endpoint_utils_extended.py +1547 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_get_endpoint_return_types.py +164 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_named_resolver.py +529 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_named_type_resolver.py +82 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_object_resolver.py +634 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_put_endpoint_return_types.py +207 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_type_cleaner.py +481 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_type_helper.py +1581 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_url_utils.py +69 -0
- pyopenapi_gen-0.8.3/tests/helpers/test_utils_helpers.py +235 -0
- pyopenapi_gen-0.8.3/tests/integration/test_generated_code_structure.py +56 -0
- pyopenapi_gen-0.8.3/tests/integrations/integrations_analysis.md +64 -0
- pyopenapi_gen-0.8.3/tests/integrations/test_business_swagger_message_type.py +100 -0
- pyopenapi_gen-0.8.3/tests/integrations/test_end_to_end_business_swagger.py +245 -0
- pyopenapi_gen-0.8.3/tests/integrations/test_end_to_end_petstore.py +134 -0
- pyopenapi_gen-0.8.3/tests/integrations/test_name_collisions.py +163 -0
- pyopenapi_gen-0.8.3/tests/specs/response_unwrapping_spec.yaml +91 -0
- pyopenapi_gen-0.8.3/tests/test_analysis_overview.md +153 -0
- pyopenapi_gen-0.8.3/tests/test_init.py +112 -0
- pyopenapi_gen-0.8.3/tests/types/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/types/test_business_swagger_integration.py +165 -0
- pyopenapi_gen-0.8.3/tests/types/test_contracts_types.py +117 -0
- pyopenapi_gen-0.8.3/tests/types/test_reference_resolver.py +94 -0
- pyopenapi_gen-0.8.3/tests/types/test_response_resolver.py +229 -0
- pyopenapi_gen-0.8.3/tests/types/test_schema_resolver.py +316 -0
- pyopenapi_gen-0.8.3/tests/types/test_type_service.py +180 -0
- pyopenapi_gen-0.8.3/tests/visit/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/generators_analysis.md +106 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_dataclass_integration.py +331 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_docstring_generator.py +219 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_endpoint_method_generator.py +207 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_match_case_response.py +228 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_request_generator.py +85 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_response_handler_generator.py +734 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_signature_generator.py +149 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/generators/test_url_args_generator.py +603 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/processors/__init__.py +1 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/processors/test_import_analyzer.py +448 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/processors/test_parameter_processor.py +429 -0
- pyopenapi_gen-0.8.3/tests/visit/endpoint/test_endpoint_visitor.py +144 -0
- pyopenapi_gen-0.8.3/tests/visit/model/__init__.py +0 -0
- pyopenapi_gen-0.8.3/tests/visit/model/test_alias_generator.py +0 -0
- pyopenapi_gen-0.8.3/tests/visit/model/test_dataclass_generator.py +0 -0
- pyopenapi_gen-0.8.3/tests/visit/model/test_enum_generator.py +774 -0
- pyopenapi_gen-0.8.3/tests/visit/test_client_visitor.py +362 -0
- pyopenapi_gen-0.8.3/tests/visit/test_model_visitor.py +641 -0
- pyopenapi_gen-0.8.3/tests/visit/test_visitor.py +193 -0
@@ -0,0 +1 @@
|
|
1
|
+
skips: ['B101', 'B404', 'B603', 'B110', 'B108']
|
@@ -0,0 +1,86 @@
|
|
1
|
+
---
|
2
|
+
description:
|
3
|
+
globs:
|
4
|
+
alwaysApply: true
|
5
|
+
---
|
6
|
+
# Cursor Rule: architecture
|
7
|
+
|
8
|
+
## Purpose
|
9
|
+
This rule introduces the crucial classes and the overall architecture of the Python OpenAPI client generator. It is intended to provide a high-level mental model for developers and AI agents working on the codebase.
|
10
|
+
|
11
|
+
---
|
12
|
+
|
13
|
+
## Core Architectural Concepts
|
14
|
+
|
15
|
+
### 1. **Intermediate Representation (IR)**
|
16
|
+
- **IRSpec, IROperation, IRParameter, IRRequestBody, IRResponse, IRSchema**
|
17
|
+
- These dataclasses represent the parsed and normalized OpenAPI spec.
|
18
|
+
- All code generation is based on this IR, not the raw OpenAPI dict.
|
19
|
+
|
20
|
+
### 1.5. **Parsing and Loading Architecture**
|
21
|
+
- **Loader (core/loader/)**
|
22
|
+
- `loader.py` - Main loader orchestration
|
23
|
+
- `operations/` - Operation parsing (parser.py, post_processor.py, request_body.py)
|
24
|
+
- `parameters/` - Parameter parsing (parser.py)
|
25
|
+
- `responses/` - Response parsing (parser.py)
|
26
|
+
- `schemas/` - Schema extraction (extractor.py)
|
27
|
+
- **Schema Parsing (core/parsing/)**
|
28
|
+
- `schema_parser.py` - Core schema parsing logic
|
29
|
+
- `unified_cycle_detection.py` - Comprehensive cycle detection system
|
30
|
+
- `context.py` - ParsingContext for state management
|
31
|
+
- `ref_resolution/` - Reference resolution helpers
|
32
|
+
- `keywords/` - Keyword-specific parsers (allOf, oneOf, etc.)
|
33
|
+
- `transformers/` - Schema transformation utilities
|
34
|
+
|
35
|
+
### 2. **Visitors**
|
36
|
+
- **Visitor (base class)**
|
37
|
+
- Generic base for all code generation visitors. Uses the visitor pattern to traverse IR nodes.
|
38
|
+
- **EndpointVisitor**
|
39
|
+
- Renders Python code for endpoint client classes and methods from IROperation nodes.
|
40
|
+
- **ModelVisitor**
|
41
|
+
- Renders Python dataclasses or enums from IRSchema nodes.
|
42
|
+
- **ClientVisitor**
|
43
|
+
- Renders the main APIClient class, which aggregates tag clients and manages transport.
|
44
|
+
- **ExceptionVisitor**
|
45
|
+
- Renders exception alias classes for HTTP error codes.
|
46
|
+
- **DocsVisitor**
|
47
|
+
- Renders Markdown documentation from the IR.
|
48
|
+
|
49
|
+
### 3. **Emitters**
|
50
|
+
- **Emitters (e.g., EndpointsEmitter, ModelsEmitter, ClientEmitter, ExceptionsEmitter, DocsEmitter)**
|
51
|
+
- Orchestrate the code generation process for each major output (endpoints, models, client, exceptions, docs).
|
52
|
+
- Use the corresponding visitor to render code, then write files to disk.
|
53
|
+
|
54
|
+
### 4. **Helpers and Utilities**
|
55
|
+
- **CodeWriter**
|
56
|
+
- Utility for building Python code with correct indentation and formatting.
|
57
|
+
- **NameSanitizer**
|
58
|
+
- Ensures all generated names are valid Python identifiers.
|
59
|
+
- **RenderContext**
|
60
|
+
- Tracks imports, file paths, and other state during code generation.
|
61
|
+
|
62
|
+
### 5. **Authentication and Transport**
|
63
|
+
- **HttpTransport (protocol), HttpxTransport (default implementation)**
|
64
|
+
- Abstract and concrete classes for HTTP communication, supporting pluggable authentication.
|
65
|
+
- **BaseAuth and plugins**
|
66
|
+
- Protocol and implementations for authentication schemes (Bearer, API key, OAuth2, etc.).
|
67
|
+
|
68
|
+
---
|
69
|
+
|
70
|
+
## Architectural Flow
|
71
|
+
1. **Spec Loading**: The OpenAPI spec is loaded and validated by the loader module.
|
72
|
+
2. **Schema Parsing**: Raw schema dictionaries are parsed into IR dataclasses using the parsing module, with unified cycle detection handling circular references.
|
73
|
+
3. **IR Construction**: Complete IRSpec object is built with all operations, parameters, responses, and schemas.
|
74
|
+
4. **Code Generation**: Emitters use visitors to traverse the IR and generate code for models, endpoints, client, exceptions, and docs.
|
75
|
+
5. **Helpers**: Utilities like CodeWriter and NameSanitizer ensure code quality and correctness.
|
76
|
+
6. **Output**: Generated code is written to disk as a ready-to-use Python package.
|
77
|
+
|
78
|
+
---
|
79
|
+
|
80
|
+
## Key Principles
|
81
|
+
- **Single Responsibility**: Each class/module has a focused purpose.
|
82
|
+
- **Extensibility**: New emitters, visitors, or plugins can be added without modifying core logic.
|
83
|
+
- **Strong Typing**: All IR and generated code is strongly typed.
|
84
|
+
- **Separation of Concerns**: Parsing, code generation, and file I/O are clearly separated.
|
85
|
+
- **Unified Cycle Detection**: A single, comprehensive system handles all circular reference scenarios consistently.
|
86
|
+
- **Modular Parsing**: Schema parsing is broken into focused, testable components.
|
@@ -0,0 +1,190 @@
|
|
1
|
+
---
|
2
|
+
description: >-
|
3
|
+
Python Coding Conventions — enforce Design-by-Contract without
|
4
|
+
external libraries, ensure Separation of Concerns, Test-Driven
|
5
|
+
Development, high coverage & first-class documentation.
|
6
|
+
globs: ["**/*.py"]
|
7
|
+
alwaysApply: true
|
8
|
+
---
|
9
|
+
|
10
|
+
# Python Coding Conventions
|
11
|
+
|
12
|
+
> **Purpose**
|
13
|
+
> Guarantee that every line of Python in this repository is **clear,
|
14
|
+
> maintainable, testable and rigorously specified by contract & tests**.
|
15
|
+
|
16
|
+
---
|
17
|
+
|
18
|
+
## 1. Core Principles
|
19
|
+
|
20
|
+
1. **Design by Contract (DbC)** — every public function/method *must*
|
21
|
+
declare and enforce **pre-conditions**, **post-conditions** &
|
22
|
+
**invariants**.
|
23
|
+
2. **Separation of Concerns** — single responsibility per module, class
|
24
|
+
and function; avoid God classes & long functions.
|
25
|
+
3. **Clarity & Readability** — code is read far more than written;
|
26
|
+
prefer explicitness over cleverness.
|
27
|
+
4. **Maintainability & Extensibility** — design for change; prefer
|
28
|
+
composition to inheritance; follow SOLID (esp. SRP, OCP, LSP, DIP).
|
29
|
+
5. **Test-Driven Development** — write the failing test first; tests are
|
30
|
+
executable specifications; aim for ≥ 90 % **branch** coverage.
|
31
|
+
6. **Comprehensive Documentation** — docstrings & type hints are
|
32
|
+
mandatory; docs express the contract.
|
33
|
+
|
34
|
+
---
|
35
|
+
|
36
|
+
## 2. Design by Contract Without External Libraries
|
37
|
+
|
38
|
+
### 2.1 Contract Enforcement
|
39
|
+
|
40
|
+
* Use **plain `assert` statements** to guard pre-conditions at the top
|
41
|
+
of the function and post-conditions at the end. Use
|
42
|
+
`__post_init__` (dataclasses) or property setters to maintain
|
43
|
+
invariants.
|
44
|
+
* Never disable contract `assert`s in production; they are part of
|
45
|
+
behaviour. Configure the runtime to **never run with `-O`/`PYTHONOPTIMIZE`**.
|
46
|
+
* Assertions must be **side-effect-free** and cheap.
|
47
|
+
|
48
|
+
```python
|
49
|
+
from dataclasses import dataclass
|
50
|
+
|
51
|
+
@dataclass
|
52
|
+
class Account:
|
53
|
+
total: int
|
54
|
+
|
55
|
+
def __post_init__(self) -> None:
|
56
|
+
# Class invariant
|
57
|
+
assert self.total >= 0, "total must be non-negative"
|
58
|
+
|
59
|
+
def deposit(self, amount: int) -> None:
|
60
|
+
"""Deposit money.
|
61
|
+
|
62
|
+
Contracts:
|
63
|
+
Pre-conditions:
|
64
|
+
- ``amount`` > 0
|
65
|
+
Post-conditions:
|
66
|
+
- ``self.total`` increased by exactly ``amount``
|
67
|
+
"""
|
68
|
+
# Pre-condition
|
69
|
+
assert amount > 0, "amount must be positive"
|
70
|
+
|
71
|
+
old_total = self.total
|
72
|
+
self.total += amount
|
73
|
+
|
74
|
+
# Post-condition
|
75
|
+
assert self.total == old_total + amount, "balance unchanged"
|
76
|
+
```
|
77
|
+
|
78
|
+
### 2.2 Contract Documentation
|
79
|
+
|
80
|
+
Extend docstrings with a **Contracts** section using the following
|
81
|
+
markers (Google style or reST is accepted):
|
82
|
+
|
83
|
+
```
|
84
|
+
Contracts:
|
85
|
+
Preconditions:
|
86
|
+
- <condition>
|
87
|
+
Postconditions:
|
88
|
+
- <condition>
|
89
|
+
Invariants:
|
90
|
+
- <condition>
|
91
|
+
```
|
92
|
+
|
93
|
+
Write conditions in **business vocabulary**, not implementation detail.
|
94
|
+
|
95
|
+
### 2.3 Contract Testing
|
96
|
+
|
97
|
+
* Unit tests **duplicate the contract** so failures show friendly
|
98
|
+
messages rather than bare AssertionErrors.
|
99
|
+
* When a contract fails, the test should describe the violated
|
100
|
+
assumption in its name.
|
101
|
+
|
102
|
+
---
|
103
|
+
|
104
|
+
## 3. Separation of Concerns & Structure
|
105
|
+
|
106
|
+
* **Modules**: logically cohesive; avoid mixed concerns.
|
107
|
+
* **Functions**: ≤ 40 logical lines; prefer pure functions.
|
108
|
+
* **Classes**: ≤ 400 logical lines & ≤ 7 public methods.
|
109
|
+
* **Layers**: domain → application/service → infrastructure. Enforce via
|
110
|
+
package structure: `domain/*`, `services/*`, `infra/*`.
|
111
|
+
* **Dependency Direction**: higher layers must not import lower layers.
|
112
|
+
|
113
|
+
---
|
114
|
+
|
115
|
+
## 4. Code Style & Readability
|
116
|
+
|
117
|
+
| Aspect | Rule |
|
118
|
+
| -------------- | ------------------------------------------------------ |
|
119
|
+
| **Formatting** | `black` (line length 120) + `ruff format` |
|
120
|
+
| **Linting** | `ruff check` for linting and import sorting |
|
121
|
+
| **Typing** | `mypy --strict` is CI-blocking |
|
122
|
+
| **Naming** | PEP 8: classes `PascalCase`, funcs `snake_case` |
|
123
|
+
| **Patterns** | Prefer **dataclasses** & **enums** over raw tuples/str |
|
124
|
+
| **Globals** | No mutable module-level state |
|
125
|
+
|
126
|
+
---
|
127
|
+
|
128
|
+
## 5. Testing Conventions
|
129
|
+
|
130
|
+
* Use **pytest** with `pytest-cov` & **hypothesis** for property tests.
|
131
|
+
* Directory: mirror package structure under `tests/`.
|
132
|
+
* Every bug fix requires a *regression test*.
|
133
|
+
* **Coverage gate**: branches ≥ 90 % enforced by CI.
|
134
|
+
* Tests are *specifications* — structure names as
|
135
|
+
**Given\_When\_Then**.
|
136
|
+
* Keep tests **fast & deterministic** (< 200 ms each).
|
137
|
+
|
138
|
+
```python
|
139
|
+
def test_deposit_increases_balance():
|
140
|
+
# Given
|
141
|
+
acc = Account(total=0)
|
142
|
+
# When
|
143
|
+
acc.deposit(50)
|
144
|
+
# Then
|
145
|
+
assert acc.total == 50
|
146
|
+
```
|
147
|
+
|
148
|
+
---
|
149
|
+
|
150
|
+
## 6. Documentation Standards
|
151
|
+
|
152
|
+
* **Docstrings**: PEP 257; include **Contracts** block where relevant.
|
153
|
+
* Use **reST** or **Google style**, but be consistent project-wide.
|
154
|
+
* Provide runnable examples (`doctest`).
|
155
|
+
* Generate API docs with **Sphinx + autodoc**; CI fails on warnings.
|
156
|
+
|
157
|
+
---
|
158
|
+
|
159
|
+
## 7. Tooling & Continuous Integration
|
160
|
+
|
161
|
+
1. **Pre-commit hooks**: `black`, `isort`, `flake8`, `mypy`.
|
162
|
+
2. **CI stages** (GitHub Actions):
|
163
|
+
|
164
|
+
1. *Static Analysis* – format, lint, type checks.
|
165
|
+
2. *Unit Tests* – `pytest -q --cov`.
|
166
|
+
3. *Docs* – `sphinx-build -n -W . ./_build`.
|
167
|
+
3. **Fail-fast** – pipeline stops on first violation.
|
168
|
+
|
169
|
+
---
|
170
|
+
|
171
|
+
## 8. Prohibited / Discouraged Patterns
|
172
|
+
|
173
|
+
* Catching broad `Exception` or using bare `except`.
|
174
|
+
* Hidden side-effects or implicit I/O in domain logic.
|
175
|
+
* Monolithic script files; always package code.
|
176
|
+
* Circular imports — resolve with adapter modules.
|
177
|
+
* Premature optimisation; measure before optimising.
|
178
|
+
|
179
|
+
---
|
180
|
+
|
181
|
+
## 9. AI / Agent Instructions
|
182
|
+
|
183
|
+
* Generated code **should include asserts and Contracts docstrings** where appropriate.
|
184
|
+
* When editing legacy code lacking contracts/tests, suggest refactor + tests as a separate task.
|
185
|
+
* Prefer clear names & explicit types over brevity.
|
186
|
+
* **Note**: The current codebase is transitioning to full Design by Contract compliance. Focus on critical business logic for contract enforcement.
|
187
|
+
|
188
|
+
---
|
189
|
+
|
190
|
+
### End of Rule
|
@@ -0,0 +1,84 @@
|
|
1
|
+
---
|
2
|
+
description:
|
3
|
+
globs:
|
4
|
+
alwaysApply: true
|
5
|
+
---
|
6
|
+
# PROJECT GOAL
|
7
|
+
|
8
|
+
The Python OpenAPI client generator must produce client code that:
|
9
|
+
|
10
|
+
## 1. Direct API Communication
|
11
|
+
- Communicates directly with the API as defined by the provided OpenAPI spec.
|
12
|
+
- Accepts strongly typed input parameters (matching the OpenAPI schema).
|
13
|
+
- Returns strongly typed responses (matching the OpenAPI schema).
|
14
|
+
|
15
|
+
## 2. Authentication & Transport
|
16
|
+
- Supports authentication and lazy loading.
|
17
|
+
- Uses a system default HTTP implementation by default, but allows the user to inject a custom HTTP class for communication.
|
18
|
+
|
19
|
+
## 3. Out-of-the-Box Functionality
|
20
|
+
- The generated code is fully functional out of the box—no stubs, placeholders, or manual implementation required for basic API communication.
|
21
|
+
|
22
|
+
## 4. IDE Support
|
23
|
+
- The generated client must support code completion and type hints in IDEs (such as PyCharm, VSCode, etc.), leveraging Python's type annotations and docstrings for maximum developer productivity.
|
24
|
+
|
25
|
+
## 5. Error Handling
|
26
|
+
- All errors that the client receives from the API must be handled by raising an exception; only successful responses are returned as response types.
|
27
|
+
|
28
|
+
---
|
29
|
+
|
30
|
+
## 6. Client Independence & Core Module
|
31
|
+
|
32
|
+
**The generated client code must be fully independent and must not require any runtime dependency on `pyopenapi_gen` itself.**
|
33
|
+
|
34
|
+
- All runtime dependencies (e.g., base transport, authentication protocols, exceptions, utility classes) must be generated into a `core` module/folder within the output package.
|
35
|
+
- The generator must provide an option to customize the name and location of this `core` folder, to support scenarios where multiple clients are generated for the same system and can share a single core implementation.
|
36
|
+
- All imports in the generated client code must be relative (e.g., `from .core.http_transport import HttpTransport`) or from the standard library/allowed third-party packages.
|
37
|
+
- No `from pyopenapi_gen...` imports should appear in the generated output.
|
38
|
+
|
39
|
+
### Example Output Structure
|
40
|
+
|
41
|
+
```
|
42
|
+
my_generated_client/
|
43
|
+
core/
|
44
|
+
http_transport.py
|
45
|
+
auth.py
|
46
|
+
exceptions.py
|
47
|
+
...
|
48
|
+
models/
|
49
|
+
...
|
50
|
+
endpoints/
|
51
|
+
...
|
52
|
+
__init__.py
|
53
|
+
py.typed
|
54
|
+
README.md
|
55
|
+
```
|
56
|
+
|
57
|
+
Or, with a shared core:
|
58
|
+
|
59
|
+
```
|
60
|
+
shared_core/
|
61
|
+
http_transport.py
|
62
|
+
auth.py
|
63
|
+
exceptions.py
|
64
|
+
...
|
65
|
+
client_a/
|
66
|
+
models/
|
67
|
+
endpoints/
|
68
|
+
...
|
69
|
+
client_b/
|
70
|
+
models/
|
71
|
+
endpoints/
|
72
|
+
...
|
73
|
+
```
|
74
|
+
*(Clients can import from the shared core as configured.)*
|
75
|
+
|
76
|
+
---
|
77
|
+
|
78
|
+
## 7. Documentation
|
79
|
+
- The generated client’s README must clearly state that it is independent and does not require `pyopenapi_gen` at runtime.
|
80
|
+
- If the core module is shared, document how to set up the import path.
|
81
|
+
|
82
|
+
---
|
83
|
+
|
84
|
+
**This ensures that the generated client is robust, portable, and easy to integrate into any Python project without extra dependencies.**
|
@@ -0,0 +1,185 @@
|
|
1
|
+
---
|
2
|
+
description:
|
3
|
+
globs: tests/**/*.py
|
4
|
+
alwaysApply: false
|
5
|
+
---
|
6
|
+
1. 🎯 Purpose
|
7
|
+
|
8
|
+
To ensure all tests — both unit and integration — are:
|
9
|
+
|
10
|
+
- Precise in intent
|
11
|
+
- Fully verifying the contract of the component under test
|
12
|
+
- Isolated from unrelated dependencies
|
13
|
+
- Described clearly for human readability and maintainability
|
14
|
+
|
15
|
+
This cursor rule must be followed both by human developers and any AI writing tests.
|
16
|
+
|
17
|
+
2. ✅ Scope of Tests
|
18
|
+
|
19
|
+
2.1 Unit Tests
|
20
|
+
|
21
|
+
Must test the smallest testable part of the application in isolation.
|
22
|
+
|
23
|
+
- Only one unit (e.g., function, class method) should be tested per test case.
|
24
|
+
- External dependencies (DBs, APIs, services, time, randomness, etc.) must be mocked or stubbed.
|
25
|
+
|
26
|
+
2.2 Integration Tests
|
27
|
+
|
28
|
+
Should test cooperation between units (e.g., service layer + repository).
|
29
|
+
|
30
|
+
- Can include real implementations of multiple components, but external system boundaries must still be mocked unless explicitly testing integrations.
|
31
|
+
- Only use real I/O for designated "integration" or "e2e" test environments, never in unit tests.
|
32
|
+
|
33
|
+
3. 📋 Test Case Structure
|
34
|
+
|
35
|
+
All tests must follow this standard format:
|
36
|
+
|
37
|
+
```python
|
38
|
+
def test_<unit_of_work>__<condition>__<expected_outcome>():
|
39
|
+
"""
|
40
|
+
Scenario:
|
41
|
+
- Description of the test scenario in 2–4 lines of natural language.
|
42
|
+
- Describe what is being tested and why it's important.
|
43
|
+
|
44
|
+
Expected Outcome:
|
45
|
+
- Explicitly state what the correct result should be (including side effects).
|
46
|
+
"""
|
47
|
+
# Arrange
|
48
|
+
# Setup necessary inputs and mocks
|
49
|
+
|
50
|
+
# Act
|
51
|
+
# Run the function or method being tested
|
52
|
+
|
53
|
+
# Assert
|
54
|
+
# Check for correct result and side effects
|
55
|
+
```
|
56
|
+
|
57
|
+
4. 🧠 AI Agent Testing Rules
|
58
|
+
|
59
|
+
When AI is tasked to write tests, it must:
|
60
|
+
|
61
|
+
- Use the above structure.
|
62
|
+
- Generate a clear, natural-language docstring summarizing the scenario and expected result.
|
63
|
+
- Mock all dependencies not directly under test.
|
64
|
+
- Avoid redundant assertions or low-value "happy path only" testing — focus on variation in input and edge cases.
|
65
|
+
- Ensure high coverage of:
|
66
|
+
- Control flow (if/else, error branches)
|
67
|
+
- Contract fidelity (input/output invariants, exceptions)
|
68
|
+
- State changes (data updates, method calls)
|
69
|
+
- Do not test third-party libraries (assume their correctness).
|
70
|
+
|
71
|
+
5. 🔬 Coverage Requirements
|
72
|
+
|
73
|
+
- All public methods and functions must be tested with 100% logical branch coverage.
|
74
|
+
- Edge cases must be included (e.g. empty list, None, 0, large inputs).
|
75
|
+
- For integration tests, ensure interface expectations between units are fully verified.
|
76
|
+
- Use pytest-cov or equivalent to enforce and review coverage.
|
77
|
+
|
78
|
+
6. 🔄 Isolation Rule
|
79
|
+
|
80
|
+
- Only the unit or flow under test may contain logic.
|
81
|
+
- Everything else (e.g., repositories, downstream APIs, services, clocks, logging, randomness) must be mocked using unittest.mock, pytest-mock, or equivalent.
|
82
|
+
- Use fixtures where applicable, but avoid overly abstract or reused test setups that reduce test clarity.
|
83
|
+
|
84
|
+
7. 🏷️ Naming & File Structure
|
85
|
+
|
86
|
+
Test files mirror the code structure: foo.py → test_foo.py
|
87
|
+
|
88
|
+
Use descriptive function names:
|
89
|
+
|
90
|
+
- ✅ test_user_creation__invalid_email__raises_error
|
91
|
+
- ❌ test_invalid_email
|
92
|
+
|
93
|
+
8. 📚 Example
|
94
|
+
|
95
|
+
```python
|
96
|
+
def test_calculate_discount__vip_customer__applies_20_percent():
|
97
|
+
"""
|
98
|
+
Scenario:
|
99
|
+
A VIP customer is eligible for a 20% discount. We want to verify that
|
100
|
+
the discount logic applies the correct rate based on the customer tier.
|
101
|
+
|
102
|
+
Expected Outcome:
|
103
|
+
The function should return the original price multiplied by 0.8.
|
104
|
+
"""
|
105
|
+
# Arrange
|
106
|
+
price = 100.0
|
107
|
+
customer = Customer(tier="VIP")
|
108
|
+
|
109
|
+
# Act
|
110
|
+
result = calculate_discount(price, customer)
|
111
|
+
|
112
|
+
# Assert
|
113
|
+
assert result == 80.0
|
114
|
+
```
|
115
|
+
|
116
|
+
9. 🧵 Integration Test Example
|
117
|
+
|
118
|
+
```python
|
119
|
+
def test_user_registration_flow__valid_data__creates_user_and_sends_email():
|
120
|
+
"""
|
121
|
+
Scenario:
|
122
|
+
A new user registers with valid data. The service should create the user,
|
123
|
+
send a welcome email, and return a success status.
|
124
|
+
|
125
|
+
Expected Outcome:
|
126
|
+
- UserRepository.save is called with correct user
|
127
|
+
- EmailService.send_welcome_email is called
|
128
|
+
- Function returns success result
|
129
|
+
"""
|
130
|
+
# Arrange
|
131
|
+
user_data = {"email": "test@example.com", "name": "Alice"}
|
132
|
+
repo = Mock()
|
133
|
+
email_service = Mock()
|
134
|
+
service = UserService(repo, email_service)
|
135
|
+
|
136
|
+
# Act
|
137
|
+
result = service.register_user(user_data)
|
138
|
+
|
139
|
+
# Assert
|
140
|
+
repo.save.assert_called_once()
|
141
|
+
email_service.send_welcome_email.assert_called_once()
|
142
|
+
assert result == {"status": "ok"}
|
143
|
+
```
|
144
|
+
## 10. Preferred Testing Framework & Style
|
145
|
+
|
146
|
+
**10.1. Framework Choice:**
|
147
|
+
- All new Python unit tests and integration tests written for this project **MUST** use the `pytest` framework.
|
148
|
+
- Existing tests written using `unittest.TestCase` **SHOULD** be refactored to `pytest` style when those files are being significantly modified or as a dedicated refactoring effort to improve test suite consistency and leverage `pytest` features.
|
149
|
+
|
150
|
+
**10.2. `pytest` Idiomatic Style:**
|
151
|
+
- **Assertions:** Tests **MUST** use plain `assert` statements for assertions (e.g., `assert result == expected`).
|
152
|
+
- **Fixtures:** Test setup, teardown, and dependency injection **MUST** be managed using `pytest` fixtures. Fixtures should be defined in the test file itself or in a relevant `conftest.py`.
|
153
|
+
- **Parameterization:** For testing multiple variations of inputs or conditions against the same test logic, `pytest.mark.parametrize` **MUST** be used to keep tests DRY (Don't Repeat Yourself) and data-driven.
|
154
|
+
- **Test Structure:** Test classes (if used) **SHOULD NOT** inherit from `unittest.TestCase`. They should be plain Python classes. Test functions can also be defined at the module level.
|
155
|
+
- **Exception Testing:** Testing for expected exceptions **MUST** use `pytest.raises` as a context manager (e.g., `with pytest.raises(SpecificException):`).
|
156
|
+
|
157
|
+
## 11. Test Suite Analysis & Documentation
|
158
|
+
|
159
|
+
**11.1. Purpose:**
|
160
|
+
- To maintain a continuous understanding of the test suite's health, coverage, and adherence to conventions.
|
161
|
+
- To provide a quick reference for the status and quality of tests within different modules.
|
162
|
+
|
163
|
+
**11.2. Root Analysis Overview (`tests/test_analysis_overview.md`):**
|
164
|
+
- **Maintenance:** This document **MUST** be kept up-to-date.
|
165
|
+
- **Content:**
|
166
|
+
- It **MUST** list all test files and their current analysis status (e.g., "Analyzed", "Needs Analysis", "Analyzed - Empty").
|
167
|
+
- It **MUST** include links to per-directory detailed analysis documents.
|
168
|
+
- **Updates:** This document **SHOULD** be updated whenever:
|
169
|
+
- New test files are added.
|
170
|
+
- Existing test files are significantly refactored or moved.
|
171
|
+
- A new pass of test analysis is completed for any part of the suite.
|
172
|
+
|
173
|
+
**11.3. Per-Directory Analysis Documents (e.g., `tests/<module>/<module>_analysis.md`):**
|
174
|
+
- **Maintenance:** These documents **SHOULD** be created or updated when a significant portion of tests within a directory/module is reviewed or refactored.
|
175
|
+
- **Content:** Each document **SHOULD** summarize:
|
176
|
+
- Overall conciseness and consistency of tests within that directory.
|
177
|
+
- Alignment with these testing conventions.
|
178
|
+
- Identification of any potentially contradictory expectations or areas for improvement specific to that module's tests.
|
179
|
+
- **Trigger for Updates:**
|
180
|
+
- After a focused review or refactoring effort on the tests within that directory.
|
181
|
+
- When the `test_analysis_overview.md` indicates a need for a detailed review of a specific area.
|
182
|
+
|
183
|
+
**11.4. Responsibility for AI Agents:**
|
184
|
+
- When an AI agent is tasked with adding new test files or performing significant refactoring of existing tests, it **MUST** update the `tests/test_analysis_overview.md` to reflect the new or changed files and their status.
|
185
|
+
- If an AI agent performs an analysis pass on a directory as requested, it **MUST** contribute to or create the relevant per-directory analysis document.
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Branch Protection Configuration
|
2
|
+
|
3
|
+
This document outlines the required GitHub branch protection settings for the `develop` branch.
|
4
|
+
|
5
|
+
## Required Settings
|
6
|
+
|
7
|
+
### Branch Protection Rules for `develop`
|
8
|
+
|
9
|
+
1. **Require pull request reviews before merging**
|
10
|
+
- Required approving reviews: 1
|
11
|
+
- Dismiss stale reviews when new commits are pushed: ✅
|
12
|
+
- Require review from code owners: ✅ (if CODEOWNERS file exists)
|
13
|
+
|
14
|
+
2. **Require status checks to pass before merging**
|
15
|
+
- Require branches to be up to date before merging: ✅
|
16
|
+
- Required status checks:
|
17
|
+
- `quality-checks (3.10)`
|
18
|
+
- `quality-checks (3.11)`
|
19
|
+
- `quality-checks (3.12)`
|
20
|
+
- `security-scan`
|
21
|
+
- `integration-tests`
|
22
|
+
|
23
|
+
3. **Require conversation resolution before merging**: ✅
|
24
|
+
|
25
|
+
4. **Require signed commits**: ❌ (optional)
|
26
|
+
|
27
|
+
5. **Require linear history**: ❌ (optional)
|
28
|
+
|
29
|
+
6. **Do not allow bypassing the above settings**: ✅
|
30
|
+
|
31
|
+
7. **Restrict pushes that create files**: ❌
|
32
|
+
|
33
|
+
8. **Allow force pushes**: ❌
|
34
|
+
|
35
|
+
9. **Allow deletions**: ❌
|
36
|
+
|
37
|
+
## How to Configure
|
38
|
+
|
39
|
+
### Via GitHub Web Interface
|
40
|
+
|
41
|
+
1. Go to your repository on GitHub
|
42
|
+
2. Click on **Settings** → **Branches**
|
43
|
+
3. Click **Add rule** or edit existing rule for `develop`
|
44
|
+
4. Configure the settings as outlined above
|
45
|
+
5. Save the branch protection rule
|
46
|
+
|
47
|
+
### Via GitHub CLI (if available)
|
48
|
+
|
49
|
+
```bash
|
50
|
+
# Example command (adjust as needed)
|
51
|
+
gh api repos/:owner/:repo/branches/develop/protection \
|
52
|
+
--method PUT \
|
53
|
+
--field required_status_checks='{"strict":true,"contexts":["quality-checks (3.10)","quality-checks (3.11)","quality-checks (3.12)","security-scan","integration-tests"]}' \
|
54
|
+
--field enforce_admins=true \
|
55
|
+
--field required_pull_request_reviews='{"required_approving_review_count":1,"dismiss_stale_reviews":true}' \
|
56
|
+
--field restrictions=null
|
57
|
+
```
|
58
|
+
|
59
|
+
## Quality Gates Enforced
|
60
|
+
|
61
|
+
The pipeline enforces the following quality gates:
|
62
|
+
|
63
|
+
### Code Quality
|
64
|
+
- ✅ **Black formatting**: Code must be properly formatted
|
65
|
+
- ✅ **Ruff linting**: No linting errors allowed
|
66
|
+
- ✅ **MyPy type checking**: Strict type checking must pass
|
67
|
+
|
68
|
+
### Testing
|
69
|
+
- ✅ **Unit tests**: All tests must pass
|
70
|
+
- ✅ **Integration tests**: End-to-end functionality verified
|
71
|
+
- ✅ **Coverage**: Minimum 90% test coverage required
|
72
|
+
- ✅ **Multi-Python version**: Tests on Python 3.10, 3.11, 3.12
|
73
|
+
|
74
|
+
### Security
|
75
|
+
- ✅ **Safety check**: No known vulnerabilities in dependencies
|
76
|
+
- ✅ **Bandit scan**: Security linting for common issues
|
77
|
+
|
78
|
+
### Functionality
|
79
|
+
- ✅ **CLI functionality**: Command-line interface works correctly
|
80
|
+
- ✅ **Client generation**: Generated clients have proper structure
|
81
|
+
- ✅ **Package building**: Project can be built successfully
|
82
|
+
|
83
|
+
## Workflow Files
|
84
|
+
|
85
|
+
- `.github/workflows/pr-checks.yml`: Runs on PRs to develop branch
|
86
|
+
- `.github/workflows/main-checks.yml`: Runs on pushes to main branch
|
87
|
+
|
88
|
+
## Local Development
|
89
|
+
|
90
|
+
Before creating a PR, run locally to ensure it will pass CI:
|
91
|
+
|
92
|
+
```bash
|
93
|
+
# Activate virtual environment
|
94
|
+
source .venv/bin/activate
|
95
|
+
|
96
|
+
# Auto-fix what's possible
|
97
|
+
make quality-fix
|
98
|
+
|
99
|
+
# Verify all quality gates pass (exactly matches CI pipeline)
|
100
|
+
make quality
|
101
|
+
|
102
|
+
# Run tests with coverage
|
103
|
+
make test-cov
|
104
|
+
```
|
105
|
+
|
106
|
+
### Individual Commands (if needed)
|
107
|
+
|
108
|
+
```bash
|
109
|
+
# Quality checks (matches CI pipeline exactly)
|
110
|
+
make format-check # Black formatting check
|
111
|
+
make lint # Ruff linting check
|
112
|
+
make typecheck # mypy type checking
|
113
|
+
make security # Bandit security scanning
|
114
|
+
|
115
|
+
# Testing
|
116
|
+
make test # Run all tests
|
117
|
+
make test-fast # Stop on first failure (for debugging)
|
118
|
+
|
119
|
+
# Auto-fixes
|
120
|
+
make format # Auto-format with Black
|
121
|
+
make lint-fix # Auto-fix linting with Ruff
|
122
|
+
```
|
123
|
+
|
124
|
+
### Why Use Make Commands?
|
125
|
+
|
126
|
+
The `make` commands ensure you're running **exactly** the same checks as the CI pipeline. This prevents the "works locally but fails in CI" problem and provides fast feedback during development.
|