pyopenapi-gen 0.8.6__tar.gz → 0.9.0__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.6 → pyopenapi_gen-0.9.0}/PKG-INFO +56 -40
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/README.md +17 -3
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/pyproject.toml +44 -4
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/__init__.py +2 -2
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/context/CLAUDE.md +284 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/context/import_collector.py +8 -8
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/core/CLAUDE.md +224 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/operations/parser.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/cycle_helpers.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/properties_parser.py +4 -4
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/schema_parser.py +4 -4
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/writers/python_construct_renderer.py +2 -2
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/emitters/CLAUDE.md +286 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/endpoints_emitter.py +1 -1
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/generator/CLAUDE.md +352 -0
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/helpers/CLAUDE.md +325 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/endpoint_utils.py +2 -2
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_cleaner.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/composition_resolver.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/finalizer.py +1 -1
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/types/CLAUDE.md +140 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/resolvers/schema_resolver.py +2 -2
- pyopenapi_gen-0.9.0/src/pyopenapi_gen/visit/CLAUDE.md +272 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/docstring_generator.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/signature_generator.py +1 -1
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/processors/parameter_processor.py +1 -1
- pyopenapi_gen-0.8.6/.bandit +0 -1
- pyopenapi_gen-0.8.6/.cursor/mcp.json +0 -10
- pyopenapi_gen-0.8.6/.cursor/rules/architecture.mdc +0 -86
- pyopenapi_gen-0.8.6/.cursor/rules/coding-conventions.mdc +0 -190
- pyopenapi_gen-0.8.6/.cursor/rules/project-goal.mdc +0 -84
- pyopenapi_gen-0.8.6/.cursor/rules/testing.mdc +0 -185
- pyopenapi_gen-0.8.6/.github/BRANCH_PROTECTION.md +0 -168
- pyopenapi_gen-0.8.6/.github/CODEOWNERS +0 -30
- pyopenapi_gen-0.8.6/.github/ISSUE_TEMPLATE/bug_report.md +0 -50
- pyopenapi_gen-0.8.6/.github/ISSUE_TEMPLATE/feature_request.md +0 -31
- pyopenapi_gen-0.8.6/.github/dependabot.yml +0 -38
- pyopenapi_gen-0.8.6/.github/workflows/ci.yml +0 -42
- pyopenapi_gen-0.8.6/.github/workflows/claude-review-trigger.yml +0 -68
- pyopenapi_gen-0.8.6/.github/workflows/claude.yml +0 -45
- pyopenapi_gen-0.8.6/.github/workflows/main-checks.yml +0 -97
- pyopenapi_gen-0.8.6/.github/workflows/pr-checks.yml +0 -141
- pyopenapi_gen-0.8.6/.github/workflows/production-release.yml +0 -170
- pyopenapi_gen-0.8.6/.github/workflows/promote-to-staging.yml +0 -65
- pyopenapi_gen-0.8.6/.github/workflows/pypi-publish.yml +0 -40
- pyopenapi_gen-0.8.6/.github/workflows/staging-publish.yml +0 -108
- pyopenapi_gen-0.8.6/.github/workflows/testpypi-publish.yml +0 -41
- pyopenapi_gen-0.8.6/.gitignore +0 -189
- pyopenapi_gen-0.8.6/.vscode/settings.json +0 -16
- pyopenapi_gen-0.8.6/CHANGELOG.md +0 -130
- pyopenapi_gen-0.8.6/CLAUDE.md +0 -670
- pyopenapi_gen-0.8.6/CONTRIBUTING.md +0 -602
- pyopenapi_gen-0.8.6/Makefile +0 -61
- pyopenapi_gen-0.8.6/RELEASE_NOTES_v0.8.5.md +0 -81
- pyopenapi_gen-0.8.6/RESPONSE_RESOLUTION_REFACTOR.md +0 -137
- pyopenapi_gen-0.8.6/TEST_MAP.md +0 -223
- pyopenapi_gen-0.8.6/debug_after_fix.py +0 -55
- pyopenapi_gen-0.8.6/debug_data_schema_names.py +0 -56
- pyopenapi_gen-0.8.6/debug_list_issue.py +0 -69
- pyopenapi_gen-0.8.6/debug_signature_issue.py +0 -56
- pyopenapi_gen-0.8.6/debug_strategy_resolver.py +0 -70
- pyopenapi_gen-0.8.6/docs/README.md +0 -79
- pyopenapi_gen-0.8.6/docs/architecture.md +0 -219
- pyopenapi_gen-0.8.6/docs/endpoint_visitor.md +0 -12
- pyopenapi_gen-0.8.6/docs/helpers.md +0 -50
- pyopenapi_gen-0.8.6/docs/ir_models.md +0 -90
- pyopenapi_gen-0.8.6/docs/line_writer.md +0 -206
- pyopenapi_gen-0.8.6/docs/loader.md +0 -11
- pyopenapi_gen-0.8.6/docs/model_visitor.md +0 -12
- pyopenapi_gen-0.8.6/docs/render_context.md +0 -11
- pyopenapi_gen-0.8.6/docs/unified_type_resolution.md +0 -206
- pyopenapi_gen-0.8.6/input/business_swagger.json +0 -11723
- pyopenapi_gen-0.8.6/input/minimal_swagger.json +0 -49
- pyopenapi_gen-0.8.6/input/minimal_syntax_test.json +0 -120
- pyopenapi_gen-0.8.6/input/test_name_collision_spec.json +0 -121
- pyopenapi_gen-0.8.6/mkdocs.yml +0 -22
- pyopenapi_gen-0.8.6/poetry.lock +0 -2237
- pyopenapi_gen-0.8.6/tests/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/auth/auth_analysis.md +0 -22
- pyopenapi_gen-0.8.6/tests/auth/test_auth_base.py +0 -116
- pyopenapi_gen-0.8.6/tests/auth/test_auth_plugins.py +0 -133
- pyopenapi_gen-0.8.6/tests/cli/cli_analysis.md +0 -64
- pyopenapi_gen-0.8.6/tests/cli/test_cli_backup_diff.py +0 -60
- pyopenapi_gen-0.8.6/tests/cli/test_cli_edge_cases.py +0 -105
- pyopenapi_gen-0.8.6/tests/cli/test_cli_edge_cases_comprehensive.py +0 -647
- pyopenapi_gen-0.8.6/tests/cli/test_cli_internal_utils.py +0 -29
- pyopenapi_gen-0.8.6/tests/cli/test_http_pagination_cli.py +0 -187
- pyopenapi_gen-0.8.6/tests/context/context_analysis.md +0 -75
- pyopenapi_gen-0.8.6/tests/context/test_file_manager.py +0 -176
- pyopenapi_gen-0.8.6/tests/context/test_import_collector.py +0 -791
- pyopenapi_gen-0.8.6/tests/context/test_render_context.py +0 -446
- pyopenapi_gen-0.8.6/tests/context/test_render_context_imports.py +0 -38
- pyopenapi_gen-0.8.6/tests/context/test_render_context_relative_paths.py +0 -103
- pyopenapi_gen-0.8.6/tests/core/core_analysis.md +0 -341
- pyopenapi_gen-0.8.6/tests/core/loader/test_extractor.py +0 -900
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/helpers_analysis.md +0 -196
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_cyclic_properties.py +0 -132
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_direct_cycle.py +0 -78
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_existing_schema.py +0 -74
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_list_response.py +0 -125
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_missing_ref.py +0 -145
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_new_schema.py +0 -142
- pyopenapi_gen-0.8.6/tests/core/parsing/common/ref_resolution/helpers/test_stripped_suffix.py +0 -156
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/keywords_analysis.md +0 -182
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/test_all_of_parser.py +0 -641
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/test_any_of_parser.py +0 -306
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/test_array_items_parser.py +0 -197
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/test_one_of_parser.py +0 -242
- pyopenapi_gen-0.8.6/tests/core/parsing/keywords/test_properties_parser.py +0 -453
- pyopenapi_gen-0.8.6/tests/core/parsing/parsing_analysis.md +0 -221
- pyopenapi_gen-0.8.6/tests/core/parsing/test_context.py +0 -269
- pyopenapi_gen-0.8.6/tests/core/parsing/test_cycle_detection.py +0 -615
- pyopenapi_gen-0.8.6/tests/core/parsing/test_cycle_helpers.py +0 -195
- pyopenapi_gen-0.8.6/tests/core/parsing/test_improved_schema_naming.py +0 -330
- pyopenapi_gen-0.8.6/tests/core/parsing/test_inline_enum_extractor.py +0 -436
- pyopenapi_gen-0.8.6/tests/core/parsing/test_inline_object_promoter.py +0 -160
- pyopenapi_gen-0.8.6/tests/core/parsing/test_logging.py +0 -281
- pyopenapi_gen-0.8.6/tests/core/parsing/test_ref_resolver.py +0 -150
- pyopenapi_gen-0.8.6/tests/core/parsing/test_schema_finalizer.py +0 -283
- pyopenapi_gen-0.8.6/tests/core/parsing/test_schema_parser.py +0 -852
- pyopenapi_gen-0.8.6/tests/core/parsing/test_schema_parser_list_response.py +0 -202
- pyopenapi_gen-0.8.6/tests/core/parsing/test_type_parser.py +0 -216
- pyopenapi_gen-0.8.6/tests/core/test_dataclass_serialization.py +0 -351
- pyopenapi_gen-0.8.6/tests/core/test_detect_circular_imports.py +0 -99
- pyopenapi_gen-0.8.6/tests/core/test_edge_cases_integration.py +0 -757
- pyopenapi_gen-0.8.6/tests/core/test_edge_cases_systematic.py +0 -603
- pyopenapi_gen-0.8.6/tests/core/test_exceptions_module.py +0 -45
- pyopenapi_gen-0.8.6/tests/core/test_forward_references.py +0 -78
- pyopenapi_gen-0.8.6/tests/core/test_http_transport.py +0 -75
- pyopenapi_gen-0.8.6/tests/core/test_import_resolution.py +0 -63
- pyopenapi_gen-0.8.6/tests/core/test_ir.py +0 -153
- pyopenapi_gen-0.8.6/tests/core/test_ir_schema.py +0 -22
- pyopenapi_gen-0.8.6/tests/core/test_loader.py +0 -595
- pyopenapi_gen-0.8.6/tests/core/test_loader_extensive.py +0 -173
- pyopenapi_gen-0.8.6/tests/core/test_loader_invalid_refs.py +0 -105
- pyopenapi_gen-0.8.6/tests/core/test_loader_malformed.py +0 -24
- pyopenapi_gen-0.8.6/tests/core/test_loader_media_types.py +0 -65
- pyopenapi_gen-0.8.6/tests/core/test_pagination.py +0 -209
- pyopenapi_gen-0.8.6/tests/core/test_parsing_context.py +0 -22
- pyopenapi_gen-0.8.6/tests/core/test_protocol_defaults.py +0 -28
- pyopenapi_gen-0.8.6/tests/core/test_schema_parser_specific_case.py +0 -40
- pyopenapi_gen-0.8.6/tests/core/test_schemas.py +0 -773
- pyopenapi_gen-0.8.6/tests/core/test_simple_self_ref_check.py +0 -142
- pyopenapi_gen-0.8.6/tests/core/test_streaming_helpers.py +0 -154
- pyopenapi_gen-0.8.6/tests/core/test_telemetry.py +0 -60
- pyopenapi_gen-0.8.6/tests/core/test_telemetry_client.py +0 -66
- pyopenapi_gen-0.8.6/tests/core/test_utils.py +0 -359
- pyopenapi_gen-0.8.6/tests/core/test_warning_collector.py +0 -49
- pyopenapi_gen-0.8.6/tests/core/writers/test_code_writer.py +0 -98
- pyopenapi_gen-0.8.6/tests/core/writers/test_documentation_writer.py +0 -480
- pyopenapi_gen-0.8.6/tests/core/writers/test_line_writer.py +0 -600
- pyopenapi_gen-0.8.6/tests/core/writers/test_python_construct_renderer_json_wizard.py +0 -213
- pyopenapi_gen-0.8.6/tests/core/writers/writers_analysis.md +0 -49
- pyopenapi_gen-0.8.6/tests/emitters/emitters_analysis.md +0 -162
- pyopenapi_gen-0.8.6/tests/emitters/test_client_emitter.py +0 -62
- pyopenapi_gen-0.8.6/tests/emitters/test_docs_emitter.py +0 -110
- pyopenapi_gen-0.8.6/tests/emitters/test_duplicate_operations.py +0 -110
- pyopenapi_gen-0.8.6/tests/emitters/test_endpoints_emitter.py +0 -881
- pyopenapi_gen-0.8.6/tests/emitters/test_exceptions_emitter.py +0 -54
- pyopenapi_gen-0.8.6/tests/emitters/test_list_response_generation.py +0 -163
- pyopenapi_gen-0.8.6/tests/emitters/test_models_emitter.py +0 -716
- pyopenapi_gen-0.8.6/tests/end_to_end/test_dataclass_serialization_e2e.py +0 -170
- pyopenapi_gen-0.8.6/tests/examples/test_developer_experience_demo.py +0 -221
- pyopenapi_gen-0.8.6/tests/generation/generation_analysis.md +0 -71
- pyopenapi_gen-0.8.6/tests/generation/test_external_core_package.py +0 -312
- pyopenapi_gen-0.8.6/tests/generation_issues/specs/minimal_addmessage_like.json +0 -112
- pyopenapi_gen-0.8.6/tests/generation_issues/test_addmessage_like_issues.py +0 -185
- pyopenapi_gen-0.8.6/tests/generation_issues/test_agent_include_parameter_typing.py +0 -126
- pyopenapi_gen-0.8.6/tests/generation_issues/test_message_batch_response_issue.py +0 -173
- pyopenapi_gen-0.8.6/tests/helpers/helpers_analysis.md +0 -247
- pyopenapi_gen-0.8.6/tests/helpers/test_array_resolver.py +0 -189
- pyopenapi_gen-0.8.6/tests/helpers/test_endpoint_utils.py +0 -722
- pyopenapi_gen-0.8.6/tests/helpers/test_endpoint_utils_extended.py +0 -1469
- pyopenapi_gen-0.8.6/tests/helpers/test_get_endpoint_return_types.py +0 -164
- pyopenapi_gen-0.8.6/tests/helpers/test_named_resolver.py +0 -531
- pyopenapi_gen-0.8.6/tests/helpers/test_named_type_resolver.py +0 -82
- pyopenapi_gen-0.8.6/tests/helpers/test_object_resolver.py +0 -643
- pyopenapi_gen-0.8.6/tests/helpers/test_put_endpoint_return_types.py +0 -207
- pyopenapi_gen-0.8.6/tests/helpers/test_type_cleaner.py +0 -481
- pyopenapi_gen-0.8.6/tests/helpers/test_type_helper.py +0 -1581
- pyopenapi_gen-0.8.6/tests/helpers/test_url_utils.py +0 -69
- pyopenapi_gen-0.8.6/tests/helpers/test_utils_helpers.py +0 -235
- pyopenapi_gen-0.8.6/tests/integration/test_generated_code_structure.py +0 -56
- pyopenapi_gen-0.8.6/tests/integrations/integrations_analysis.md +0 -64
- pyopenapi_gen-0.8.6/tests/integrations/test_business_swagger_message_type.py +0 -100
- pyopenapi_gen-0.8.6/tests/integrations/test_end_to_end_business_swagger.py +0 -221
- pyopenapi_gen-0.8.6/tests/integrations/test_end_to_end_petstore.py +0 -134
- pyopenapi_gen-0.8.6/tests/integrations/test_name_collisions.py +0 -163
- pyopenapi_gen-0.8.6/tests/specs/response_unwrapping_spec.yaml +0 -91
- pyopenapi_gen-0.8.6/tests/test_analysis_overview.md +0 -153
- pyopenapi_gen-0.8.6/tests/test_init.py +0 -112
- pyopenapi_gen-0.8.6/tests/types/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/types/test_business_swagger_integration.py +0 -166
- pyopenapi_gen-0.8.6/tests/types/test_contracts_types.py +0 -114
- pyopenapi_gen-0.8.6/tests/types/test_reference_resolver.py +0 -94
- pyopenapi_gen-0.8.6/tests/types/test_response_resolver.py +0 -388
- pyopenapi_gen-0.8.6/tests/types/test_response_strategy.py +0 -450
- pyopenapi_gen-0.8.6/tests/types/test_response_strategy_simplified.py +0 -328
- pyopenapi_gen-0.8.6/tests/types/test_schema_resolver.py +0 -643
- pyopenapi_gen-0.8.6/tests/types/test_type_service.py +0 -180
- pyopenapi_gen-0.8.6/tests/visit/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/visit/endpoint/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/generators_analysis.md +0 -106
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_dataclass_integration.py +0 -331
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_docstring_generator.py +0 -222
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_endpoint_method_generator.py +0 -243
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_match_case_response.py +0 -241
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_request_generator.py +0 -85
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_response_handler_generator.py +0 -736
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_response_handler_generator_strategy.py +0 -429
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_signature_generator.py +0 -158
- pyopenapi_gen-0.8.6/tests/visit/endpoint/generators/test_url_args_generator.py +0 -603
- pyopenapi_gen-0.8.6/tests/visit/endpoint/processors/__init__.py +0 -1
- pyopenapi_gen-0.8.6/tests/visit/endpoint/processors/test_import_analyzer.py +0 -446
- pyopenapi_gen-0.8.6/tests/visit/endpoint/processors/test_import_analyzer.py.bak +0 -450
- pyopenapi_gen-0.8.6/tests/visit/endpoint/processors/test_parameter_processor.py +0 -429
- pyopenapi_gen-0.8.6/tests/visit/endpoint/test_endpoint_visitor.py +0 -144
- pyopenapi_gen-0.8.6/tests/visit/model/__init__.py +0 -0
- pyopenapi_gen-0.8.6/tests/visit/model/test_alias_generator.py +0 -0
- pyopenapi_gen-0.8.6/tests/visit/model/test_dataclass_generator.py +0 -0
- pyopenapi_gen-0.8.6/tests/visit/model/test_dataclass_generator_json_wizard.py +0 -248
- pyopenapi_gen-0.8.6/tests/visit/model/test_enum_generator.py +0 -774
- pyopenapi_gen-0.8.6/tests/visit/test_client_visitor.py +0 -362
- pyopenapi_gen-0.8.6/tests/visit/test_model_visitor.py +0 -643
- pyopenapi_gen-0.8.6/tests/visit/test_visitor.py +0 -193
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/LICENSE +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/__main__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/cli.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/context/file_manager.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/context/render_context.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/auth/base.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/auth/plugins.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/exceptions.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/http_transport.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/loader.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/operations/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/operations/post_processor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/operations/request_body.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/parameters/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/parameters/parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/responses/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/responses/parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/schemas/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/loader/schemas/extractor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/pagination.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/cyclic_properties.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/direct_cycle.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/existing_schema.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/list_response.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/resolve_schema_ref.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/common/type_parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/context.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/all_of_parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/any_of_parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/array_items_parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/keywords/one_of_parser.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/schema_finalizer.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/transformers/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/transformers/inline_object_promoter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/parsing/unified_cycle_detection.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/postprocess_manager.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/schemas.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/streaming_helpers.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/telemetry.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/utils.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/warning_collector.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/writers/code_writer.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/writers/documentation_writer.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core/writers/line_writer.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/core_package_template/README.md +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emit/models_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/client_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/core_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/docs_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/exceptions_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/emitters/models_emitter.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/generator/client_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_helper.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/array_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/named_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/object_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/primitive_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/type_resolution/resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/helpers/url_utils.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/http_types.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/ir.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/py.typed +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/contracts/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/contracts/protocols.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/contracts/types.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/resolvers/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/resolvers/reference_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/resolvers/response_resolver.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/services/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/services/type_service.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/strategies/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/types/strategies/response_strategy.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/client_visitor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/docs_visitor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/endpoint_visitor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/request_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/generators/url_args_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/processors/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/endpoint/processors/import_analyzer.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/exception_visitor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/model/__init__.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/model/alias_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/model/dataclass_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/model/enum_generator.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/model/model_visitor.py +0 -0
- {pyopenapi_gen-0.8.6 → pyopenapi_gen-0.9.0}/src/pyopenapi_gen/visit/visitor.py +0 -0
@@ -1,19 +1,14 @@
|
|
1
|
-
Metadata-Version: 2.
|
1
|
+
Metadata-Version: 2.3
|
2
2
|
Name: pyopenapi-gen
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.9.0
|
4
4
|
Summary: Modern, async-first Python client generator for OpenAPI specifications with advanced cycle detection and unified type resolution
|
5
|
-
Project-URL: Homepage, https://github.com/your-org/pyopenapi-gen
|
6
|
-
Project-URL: Documentation, https://github.com/your-org/pyopenapi-gen/blob/main/README.md
|
7
|
-
Project-URL: Repository, https://github.com/your-org/pyopenapi-gen
|
8
|
-
Project-URL: Issues, https://github.com/your-org/pyopenapi-gen/issues
|
9
|
-
Project-URL: Changelog, https://github.com/your-org/pyopenapi-gen/blob/main/CHANGELOG.md
|
10
|
-
Project-URL: Bug Reports, https://github.com/your-org/pyopenapi-gen/issues
|
11
|
-
Project-URL: Source Code, https://github.com/your-org/pyopenapi-gen
|
12
|
-
Author-email: Mindhive Oy <contact@mindhive.fi>
|
13
|
-
Maintainer-email: Ville Venäläinen | Mindhive Oy <ville@mindhive.fi>
|
14
5
|
License: MIT
|
15
|
-
|
16
|
-
|
6
|
+
Keywords: openapi,swagger,client,generator,async,python,api,http,rest,type-safe,code-generation,enterprise
|
7
|
+
Author: Mindhive Oy
|
8
|
+
Author-email: contact@mindhive.fi
|
9
|
+
Maintainer: Ville Venäläinen | Mindhive Oy
|
10
|
+
Maintainer-email: ville@mindhive.fi
|
11
|
+
Requires-Python: >=3.12,<4.0.0
|
17
12
|
Classifier: Development Status :: 4 - Beta
|
18
13
|
Classifier: Environment :: Console
|
19
14
|
Classifier: Framework :: AsyncIO
|
@@ -21,39 +16,45 @@ Classifier: Intended Audience :: Developers
|
|
21
16
|
Classifier: License :: OSI Approved :: MIT License
|
22
17
|
Classifier: Natural Language :: English
|
23
18
|
Classifier: Operating System :: MacOS
|
24
|
-
Classifier: Operating System :: Microsoft :: Windows
|
25
19
|
Classifier: Operating System :: POSIX :: Linux
|
20
|
+
Classifier: Operating System :: Microsoft :: Windows
|
26
21
|
Classifier: Programming Language :: Python :: 3
|
27
|
-
Classifier: Programming Language :: Python :: 3 :: Only
|
28
22
|
Classifier: Programming Language :: Python :: 3.12
|
23
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
29
24
|
Classifier: Topic :: Internet :: WWW/HTTP :: HTTP Servers
|
30
25
|
Classifier: Topic :: Software Development :: Code Generators
|
31
26
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
32
27
|
Classifier: Topic :: System :: Networking
|
33
28
|
Classifier: Typing :: Typed
|
34
|
-
Requires-Python: <4.0.0,>=3.12
|
35
|
-
Requires-Dist: click>=8.0.0
|
36
|
-
Requires-Dist: dataclass-wizard>=0.22.0
|
37
|
-
Requires-Dist: httpx>=0.24.0
|
38
|
-
Requires-Dist: openapi-core>=0.19
|
39
|
-
Requires-Dist: openapi-spec-validator>=0.7
|
40
|
-
Requires-Dist: pyyaml>=6.0
|
41
|
-
Requires-Dist: typer>=0.12.0
|
42
29
|
Provides-Extra: dev
|
43
|
-
Requires-Dist:
|
44
|
-
Requires-Dist:
|
45
|
-
Requires-Dist:
|
46
|
-
Requires-Dist:
|
47
|
-
Requires-Dist:
|
48
|
-
Requires-Dist:
|
49
|
-
Requires-Dist:
|
50
|
-
Requires-Dist:
|
51
|
-
Requires-Dist:
|
52
|
-
Requires-Dist:
|
53
|
-
Requires-Dist:
|
54
|
-
Requires-Dist:
|
55
|
-
Requires-Dist:
|
56
|
-
Requires-Dist:
|
30
|
+
Requires-Dist: PyYAML (>=6.0)
|
31
|
+
Requires-Dist: bandit[toml] (>=1.7.0) ; extra == "dev"
|
32
|
+
Requires-Dist: black (>=23.0) ; extra == "dev"
|
33
|
+
Requires-Dist: click (>=8.0.0,<9.0.0)
|
34
|
+
Requires-Dist: dataclass-wizard (>=0.22.0)
|
35
|
+
Requires-Dist: dataclass-wizard (>=0.22.0) ; extra == "dev"
|
36
|
+
Requires-Dist: httpx (>=0.24.0)
|
37
|
+
Requires-Dist: httpx (>=0.24.0) ; extra == "dev"
|
38
|
+
Requires-Dist: mypy (>=1.7) ; extra == "dev"
|
39
|
+
Requires-Dist: openapi-core (>=0.19)
|
40
|
+
Requires-Dist: openapi-spec-validator (>=0.7)
|
41
|
+
Requires-Dist: pytest (>=7.0) ; extra == "dev"
|
42
|
+
Requires-Dist: pytest-asyncio (>=0.20.0) ; extra == "dev"
|
43
|
+
Requires-Dist: pytest-cov (>=4.0) ; extra == "dev"
|
44
|
+
Requires-Dist: pytest-timeout (>=2.1.0) ; extra == "dev"
|
45
|
+
Requires-Dist: pytest-xdist (>=3.0.0) ; extra == "dev"
|
46
|
+
Requires-Dist: ruff (>=0.4) ; extra == "dev"
|
47
|
+
Requires-Dist: safety (>=2.0.0) ; extra == "dev"
|
48
|
+
Requires-Dist: typer (>=0.12.0,<0.14.0)
|
49
|
+
Requires-Dist: types-pyyaml (>=6.0.12) ; extra == "dev"
|
50
|
+
Requires-Dist: types-toml (>=0.10.8) ; extra == "dev"
|
51
|
+
Project-URL: Bug Reports, https://github.com/your-org/pyopenapi-gen/issues
|
52
|
+
Project-URL: Changelog, https://github.com/your-org/pyopenapi-gen/blob/main/CHANGELOG.md
|
53
|
+
Project-URL: Documentation, https://github.com/your-org/pyopenapi-gen/blob/main/README.md
|
54
|
+
Project-URL: Homepage, https://github.com/your-org/pyopenapi-gen
|
55
|
+
Project-URL: Issues, https://github.com/your-org/pyopenapi-gen/issues
|
56
|
+
Project-URL: Repository, https://github.com/your-org/pyopenapi-gen
|
57
|
+
Project-URL: Source Code, https://github.com/your-org/pyopenapi-gen
|
57
58
|
Description-Content-Type: text/markdown
|
58
59
|
|
59
60
|
# PyOpenAPI Generator
|
@@ -99,7 +100,7 @@ poetry add pyopenapi-gen
|
|
99
100
|
|
100
101
|
### 1. Generate Your First Client
|
101
102
|
```bash
|
102
|
-
pyopenapi-gen
|
103
|
+
pyopenapi-gen openapi.yaml \
|
103
104
|
--project-root . \
|
104
105
|
--output-package my_api_client
|
105
106
|
```
|
@@ -127,7 +128,7 @@ asyncio.run(main())
|
|
127
128
|
|
128
129
|
### Standalone Client (Default)
|
129
130
|
```bash
|
130
|
-
pyopenapi-gen
|
131
|
+
pyopenapi-gen openapi.yaml \
|
131
132
|
--project-root . \
|
132
133
|
--output-package my_api_client
|
133
134
|
```
|
@@ -135,7 +136,7 @@ Creates self-contained client with embedded core dependencies.
|
|
135
136
|
|
136
137
|
### Shared Core (Multiple Clients)
|
137
138
|
```bash
|
138
|
-
pyopenapi-gen
|
139
|
+
pyopenapi-gen openapi.yaml \
|
139
140
|
--project-root . \
|
140
141
|
--output-package clients.api_client \
|
141
142
|
--core-package clients.core
|
@@ -358,6 +359,20 @@ make typecheck # Type checking with mypy
|
|
358
359
|
make security # Security scanning with Bandit
|
359
360
|
```
|
360
361
|
|
362
|
+
### Release Process
|
363
|
+
The project uses **automated semantic versioning** with conventional commits:
|
364
|
+
|
365
|
+
```bash
|
366
|
+
# Conventional commit format triggers automatic releases
|
367
|
+
git commit -m "feat(auth): add OAuth2 support" # → Minor version bump
|
368
|
+
git commit -m "fix(parser): resolve memory leak" # → Patch version bump
|
369
|
+
|
370
|
+
# Push to main triggers automatic PyPI release
|
371
|
+
git push origin main
|
372
|
+
```
|
373
|
+
|
374
|
+
All releases are automatically published to PyPI with generated changelogs. See [Release Management](CLAUDE.md#release-management--semantic-versioning) for complete details.
|
375
|
+
|
361
376
|
See our [Contributing Guide](CONTRIBUTING.md) for detailed information on:
|
362
377
|
- 📋 Development setup and workflow
|
363
378
|
- 🧪 Testing guidelines and standards
|
@@ -381,3 +396,4 @@ Generated clients are self-contained and can be distributed under any license co
|
|
381
396
|
---
|
382
397
|
|
383
398
|
**Made with ❤️ for the Python community**
|
399
|
+
|
@@ -41,7 +41,7 @@ poetry add pyopenapi-gen
|
|
41
41
|
|
42
42
|
### 1. Generate Your First Client
|
43
43
|
```bash
|
44
|
-
pyopenapi-gen
|
44
|
+
pyopenapi-gen openapi.yaml \
|
45
45
|
--project-root . \
|
46
46
|
--output-package my_api_client
|
47
47
|
```
|
@@ -69,7 +69,7 @@ asyncio.run(main())
|
|
69
69
|
|
70
70
|
### Standalone Client (Default)
|
71
71
|
```bash
|
72
|
-
pyopenapi-gen
|
72
|
+
pyopenapi-gen openapi.yaml \
|
73
73
|
--project-root . \
|
74
74
|
--output-package my_api_client
|
75
75
|
```
|
@@ -77,7 +77,7 @@ Creates self-contained client with embedded core dependencies.
|
|
77
77
|
|
78
78
|
### Shared Core (Multiple Clients)
|
79
79
|
```bash
|
80
|
-
pyopenapi-gen
|
80
|
+
pyopenapi-gen openapi.yaml \
|
81
81
|
--project-root . \
|
82
82
|
--output-package clients.api_client \
|
83
83
|
--core-package clients.core
|
@@ -300,6 +300,20 @@ make typecheck # Type checking with mypy
|
|
300
300
|
make security # Security scanning with Bandit
|
301
301
|
```
|
302
302
|
|
303
|
+
### Release Process
|
304
|
+
The project uses **automated semantic versioning** with conventional commits:
|
305
|
+
|
306
|
+
```bash
|
307
|
+
# Conventional commit format triggers automatic releases
|
308
|
+
git commit -m "feat(auth): add OAuth2 support" # → Minor version bump
|
309
|
+
git commit -m "fix(parser): resolve memory leak" # → Patch version bump
|
310
|
+
|
311
|
+
# Push to main triggers automatic PyPI release
|
312
|
+
git push origin main
|
313
|
+
```
|
314
|
+
|
315
|
+
All releases are automatically published to PyPI with generated changelogs. See [Release Management](CLAUDE.md#release-management--semantic-versioning) for complete details.
|
316
|
+
|
303
317
|
See our [Contributing Guide](CONTRIBUTING.md) for detailed information on:
|
304
318
|
- 📋 Development setup and workflow
|
305
319
|
- 🧪 Testing guidelines and standards
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
4
4
|
|
5
5
|
[project]
|
6
6
|
name = "pyopenapi-gen"
|
7
|
-
version = "0.
|
7
|
+
version = "0.9.0"
|
8
8
|
description = "Modern, async-first Python client generator for OpenAPI specifications with advanced cycle detection and unified type resolution"
|
9
9
|
authors = [{ name = "Mindhive Oy", email = "contact@mindhive.fi" }]
|
10
10
|
maintainers = [{ name = "Ville Venäläinen | Mindhive Oy", email = "ville@mindhive.fi" }]
|
@@ -14,8 +14,8 @@ dependencies = [
|
|
14
14
|
"openapi-spec-validator>=0.7",
|
15
15
|
"openapi-core>=0.19",
|
16
16
|
"PyYAML>=6.0",
|
17
|
-
"typer>=0.12.0",
|
18
|
-
"click>=8.0.0",
|
17
|
+
"typer>=0.12.0,<0.14.0",
|
18
|
+
"click>=8.0.0,<9.0.0",
|
19
19
|
"httpx>=0.24.0",
|
20
20
|
"dataclass-wizard>=0.22.0",
|
21
21
|
]
|
@@ -111,6 +111,7 @@ python_files = ["test_*.py"]
|
|
111
111
|
python_functions = ["test_"]
|
112
112
|
log_cli = false
|
113
113
|
log_cli_level = "WARNING"
|
114
|
+
asyncio_mode = "auto"
|
114
115
|
asyncio_default_fixture_loop_scope = "function"
|
115
116
|
# For details on registering custom marks, see:
|
116
117
|
# https://docs.pytest.org/en/stable/how-to/mark.html
|
@@ -121,8 +122,47 @@ markers = [
|
|
121
122
|
|
122
123
|
[tool.poetry.group.dev.dependencies]
|
123
124
|
types-pyyaml = "^6.0.12.20250516"
|
124
|
-
bandit = {extras = ["toml"], version = "^1.8.
|
125
|
+
bandit = {extras = ["toml"], version = "^1.8.6"}
|
125
126
|
pytest-timeout = "^2.4.0"
|
127
|
+
pytest-asyncio = "^1.1.0"
|
128
|
+
black = "^25.1.0"
|
129
|
+
ruff = "^0.12.3"
|
130
|
+
mypy = "^1.17.0"
|
131
|
+
commitizen = "^3.29.0"
|
132
|
+
python-semantic-release = "^9.12.0"
|
133
|
+
pytest-xdist = "^3.8.0"
|
134
|
+
pytest-cov = "^6.2.1"
|
135
|
+
build = "^1.2.0"
|
126
136
|
|
127
137
|
[project.scripts]
|
128
138
|
pyopenapi-gen = "pyopenapi_gen.cli:app"
|
139
|
+
|
140
|
+
[tool.commitizen]
|
141
|
+
name = "cz_conventional_commits"
|
142
|
+
version = "0.9.0"
|
143
|
+
version_files = [
|
144
|
+
"pyproject.toml:version",
|
145
|
+
"src/pyopenapi_gen/__init__.py:__version__"
|
146
|
+
]
|
147
|
+
tag_format = "v$version"
|
148
|
+
major_version_zero = false
|
149
|
+
changelog_file = "CHANGELOG.md"
|
150
|
+
changelog_format = "## [$version] - $date\\n\\n$changes"
|
151
|
+
commit_parser = "^(?P<change_type>feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(?:\\((?P<scope>[^)]+)\\))?!?:\\s(?P<message>.+)$"
|
152
|
+
bump_message = "bump: version $current_version → $new_version"
|
153
|
+
|
154
|
+
[tool.semantic_release]
|
155
|
+
version_toml = ["pyproject.toml:project.version", "pyproject.toml:tool.commitizen.version"]
|
156
|
+
version_pattern = [
|
157
|
+
"src/pyopenapi_gen/__init__.py:__version__: str = \"{version}\""
|
158
|
+
]
|
159
|
+
branch = "main"
|
160
|
+
upload_to_pypi = true
|
161
|
+
upload_to_repository = true
|
162
|
+
commit_message = "chore(release): {version}"
|
163
|
+
tag_commit = true
|
164
|
+
changelog_file = "CHANGELOG.md"
|
165
|
+
changelog_format = "# Changelog\\n\\n{changelog}"
|
166
|
+
hvcs = "github"
|
167
|
+
commit_parser = "conventional"
|
168
|
+
major_on_zero = false
|
@@ -42,8 +42,8 @@ __all__ = [
|
|
42
42
|
"WarningCollector",
|
43
43
|
]
|
44
44
|
|
45
|
-
# Semantic version of the generator core –
|
46
|
-
__version__: str = "0.
|
45
|
+
# Semantic version of the generator core – automatically managed by semantic-release.
|
46
|
+
__version__: str = "0.9.0"
|
47
47
|
|
48
48
|
|
49
49
|
# ---------------------------------------------------------------------------
|
@@ -0,0 +1,284 @@
|
|
1
|
+
# context/ - Rendering Context Management
|
2
|
+
|
3
|
+
## Why This Folder?
|
4
|
+
Manage stateful information during code generation: imports, templates, file paths, and rendering state. Provides clean interface between visitors and emitters.
|
5
|
+
|
6
|
+
## Key Dependencies
|
7
|
+
- **Input**: Path configuration, package names, template data
|
8
|
+
- **Output**: Import statements, resolved file paths, template rendering
|
9
|
+
- **Used by**: All visitors and emitters for consistent code generation
|
10
|
+
|
11
|
+
## Essential Architecture
|
12
|
+
|
13
|
+
### 1. Context Lifecycle
|
14
|
+
```python
|
15
|
+
# 1. Create context for generation session
|
16
|
+
context = RenderContext(project_root="/path/to/project", output_package="my_client")
|
17
|
+
|
18
|
+
# 2. Visitors use context for type resolution and imports
|
19
|
+
visitor.visit_schema(schema, context) # Registers imports
|
20
|
+
|
21
|
+
# 3. Emitters use context for file organization
|
22
|
+
emitter.emit_models(schemas, context) # Consumes imports
|
23
|
+
```
|
24
|
+
|
25
|
+
### 2. State Management
|
26
|
+
```python
|
27
|
+
# render_context.py
|
28
|
+
class RenderContext:
|
29
|
+
def __init__(self, project_root: Path, output_package: str):
|
30
|
+
self.import_collector = ImportCollector()
|
31
|
+
self.file_manager = FileManager(project_root)
|
32
|
+
self.template_vars = {}
|
33
|
+
self.output_package = output_package
|
34
|
+
self.forward_refs = set()
|
35
|
+
```
|
36
|
+
|
37
|
+
## Critical Components
|
38
|
+
|
39
|
+
### render_context.py
|
40
|
+
**Purpose**: Main context object passed through generation pipeline
|
41
|
+
```python
|
42
|
+
class RenderContext:
|
43
|
+
def add_import(self, import_statement: str) -> None:
|
44
|
+
"""Register import for current file being generated"""
|
45
|
+
self.import_collector.add_import(import_statement)
|
46
|
+
|
47
|
+
def get_imports(self) -> List[str]:
|
48
|
+
"""Get sorted, deduplicated imports for current file"""
|
49
|
+
return self.import_collector.get_sorted_imports()
|
50
|
+
|
51
|
+
def clear_imports(self) -> None:
|
52
|
+
"""Clear imports for next file generation"""
|
53
|
+
self.import_collector.clear()
|
54
|
+
|
55
|
+
def resolve_relative_import(self, from_package: str, to_package: str) -> str:
|
56
|
+
"""Convert absolute import to relative import"""
|
57
|
+
return self.import_collector.make_relative_import(from_package, to_package)
|
58
|
+
```
|
59
|
+
|
60
|
+
### import_collector.py
|
61
|
+
**Purpose**: Collect and manage import statements during code generation
|
62
|
+
```python
|
63
|
+
class ImportCollector:
|
64
|
+
def __init__(self):
|
65
|
+
self.imports: Set[str] = set()
|
66
|
+
self.from_imports: Dict[str, Set[str]] = defaultdict(set)
|
67
|
+
|
68
|
+
def add_import(self, import_statement: str) -> None:
|
69
|
+
"""Add import statement, handling both 'import' and 'from' forms"""
|
70
|
+
if import_statement.startswith("from "):
|
71
|
+
self.parse_from_import(import_statement)
|
72
|
+
else:
|
73
|
+
self.imports.add(import_statement)
|
74
|
+
|
75
|
+
def get_sorted_imports(self) -> List[str]:
|
76
|
+
"""Return sorted imports: stdlib, third-party, local"""
|
77
|
+
return self.sort_imports_by_category()
|
78
|
+
```
|
79
|
+
|
80
|
+
### file_manager.py
|
81
|
+
**Purpose**: Handle file operations and path resolution
|
82
|
+
```python
|
83
|
+
class FileManager:
|
84
|
+
def __init__(self, project_root: Path):
|
85
|
+
self.project_root = project_root
|
86
|
+
|
87
|
+
def write_file(self, file_path: Path, content: str) -> None:
|
88
|
+
"""Write file with proper directory creation"""
|
89
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
90
|
+
file_path.write_text(content)
|
91
|
+
|
92
|
+
def resolve_package_path(self, package_name: str) -> Path:
|
93
|
+
"""Convert package.name to file system path"""
|
94
|
+
parts = package_name.split(".")
|
95
|
+
return self.project_root / Path(*parts)
|
96
|
+
```
|
97
|
+
|
98
|
+
## Import Management Patterns
|
99
|
+
|
100
|
+
### 1. Import Categories
|
101
|
+
```python
|
102
|
+
# import_collector.py
|
103
|
+
def categorize_import(self, import_statement: str) -> ImportCategory:
|
104
|
+
"""Categorize imports for proper sorting"""
|
105
|
+
if self.is_stdlib_import(import_statement):
|
106
|
+
return ImportCategory.STDLIB
|
107
|
+
elif self.is_third_party_import(import_statement):
|
108
|
+
return ImportCategory.THIRD_PARTY
|
109
|
+
else:
|
110
|
+
return ImportCategory.LOCAL
|
111
|
+
```
|
112
|
+
|
113
|
+
### 2. From Import Consolidation
|
114
|
+
```python
|
115
|
+
# Convert multiple from imports to single statement
|
116
|
+
# "from typing import List"
|
117
|
+
# "from typing import Dict"
|
118
|
+
# →
|
119
|
+
# "from typing import Dict, List"
|
120
|
+
|
121
|
+
def consolidate_from_imports(self) -> List[str]:
|
122
|
+
consolidated = []
|
123
|
+
for module, imports in self.from_imports.items():
|
124
|
+
sorted_imports = sorted(imports)
|
125
|
+
consolidated.append(f"from {module} import {', '.join(sorted_imports)}")
|
126
|
+
return consolidated
|
127
|
+
```
|
128
|
+
|
129
|
+
### 3. Relative Import Conversion
|
130
|
+
```python
|
131
|
+
def make_relative_import(self, from_package: str, to_package: str) -> str:
|
132
|
+
"""Convert absolute import to relative import"""
|
133
|
+
# from my_client.models.user import User
|
134
|
+
# →
|
135
|
+
# from ..models.user import User (when called from my_client.endpoints)
|
136
|
+
|
137
|
+
from_parts = from_package.split(".")
|
138
|
+
to_parts = to_package.split(".")
|
139
|
+
|
140
|
+
# Find common prefix
|
141
|
+
common_len = self.find_common_prefix_length(from_parts, to_parts)
|
142
|
+
|
143
|
+
# Calculate relative depth
|
144
|
+
relative_depth = len(from_parts) - common_len
|
145
|
+
prefix = "." * relative_depth
|
146
|
+
|
147
|
+
# Build relative import
|
148
|
+
remaining_path = ".".join(to_parts[common_len:])
|
149
|
+
return f"from {prefix}{remaining_path} import"
|
150
|
+
```
|
151
|
+
|
152
|
+
## Template Management
|
153
|
+
|
154
|
+
### 1. Template Variables
|
155
|
+
```python
|
156
|
+
# Store template variables for consistent rendering
|
157
|
+
context.template_vars.update({
|
158
|
+
"client_name": "MyAPIClient",
|
159
|
+
"base_url": "https://api.example.com",
|
160
|
+
"version": "1.0.0",
|
161
|
+
"auth_type": "bearer"
|
162
|
+
})
|
163
|
+
```
|
164
|
+
|
165
|
+
### 2. Template Rendering
|
166
|
+
```python
|
167
|
+
def render_template(self, template: str, **kwargs) -> str:
|
168
|
+
"""Render template with context variables"""
|
169
|
+
all_vars = {**self.template_vars, **kwargs}
|
170
|
+
return template.format(**all_vars)
|
171
|
+
```
|
172
|
+
|
173
|
+
## Dependencies on Other Systems
|
174
|
+
|
175
|
+
### From types/
|
176
|
+
- Implements `TypeContext` protocol for type resolution
|
177
|
+
- Provides import registration for complex types
|
178
|
+
|
179
|
+
### From visit/
|
180
|
+
- Receives import registration during code generation
|
181
|
+
- Provides path resolution for relative imports
|
182
|
+
|
183
|
+
### From emitters/
|
184
|
+
- Provides file writing capabilities
|
185
|
+
- Supplies consolidated imports for file headers
|
186
|
+
|
187
|
+
## Testing Requirements
|
188
|
+
|
189
|
+
### Import Management Tests
|
190
|
+
```python
|
191
|
+
def test_import_collector__multiple_from_imports__consolidates_correctly():
|
192
|
+
# Arrange
|
193
|
+
collector = ImportCollector()
|
194
|
+
collector.add_import("from typing import List")
|
195
|
+
collector.add_import("from typing import Dict")
|
196
|
+
|
197
|
+
# Act
|
198
|
+
imports = collector.get_sorted_imports()
|
199
|
+
|
200
|
+
# Assert
|
201
|
+
assert "from typing import Dict, List" in imports
|
202
|
+
```
|
203
|
+
|
204
|
+
### Path Resolution Tests
|
205
|
+
```python
|
206
|
+
def test_file_manager__package_path__resolves_correctly():
|
207
|
+
# Test package name to file path conversion
|
208
|
+
manager = FileManager(Path("/project"))
|
209
|
+
path = manager.resolve_package_path("my_client.models")
|
210
|
+
|
211
|
+
assert path == Path("/project/my_client/models")
|
212
|
+
```
|
213
|
+
|
214
|
+
## Extension Points
|
215
|
+
|
216
|
+
### Custom Import Sorting
|
217
|
+
```python
|
218
|
+
class CustomImportCollector(ImportCollector):
|
219
|
+
def sort_imports_by_category(self) -> List[str]:
|
220
|
+
# Custom import sorting logic
|
221
|
+
# Example: Group all async imports together
|
222
|
+
pass
|
223
|
+
```
|
224
|
+
|
225
|
+
### Template System Integration
|
226
|
+
```python
|
227
|
+
def add_template_engine(self, engine: TemplateEngine) -> None:
|
228
|
+
"""Add custom template engine (Jinja2, etc.)"""
|
229
|
+
self.template_engine = engine
|
230
|
+
|
231
|
+
def render_template(self, template_name: str, **kwargs) -> str:
|
232
|
+
"""Render template using custom engine"""
|
233
|
+
return self.template_engine.render(template_name, **kwargs)
|
234
|
+
```
|
235
|
+
|
236
|
+
## Critical Implementation Details
|
237
|
+
|
238
|
+
### Thread Safety
|
239
|
+
```python
|
240
|
+
# Context is NOT thread-safe by design
|
241
|
+
# Each generation session gets its own context instance
|
242
|
+
def create_context() -> RenderContext:
|
243
|
+
return RenderContext(project_root, output_package)
|
244
|
+
```
|
245
|
+
|
246
|
+
### Memory Management
|
247
|
+
```python
|
248
|
+
# Clear context between files to prevent memory leaks
|
249
|
+
def emit_file(self, file_path: Path, generator_func: Callable) -> None:
|
250
|
+
self.context.clear_imports()
|
251
|
+
|
252
|
+
# Generate code
|
253
|
+
code = generator_func(self.context)
|
254
|
+
|
255
|
+
# Write file with imports
|
256
|
+
imports = self.context.get_imports()
|
257
|
+
final_code = self.combine_imports_and_code(imports, code)
|
258
|
+
|
259
|
+
self.file_manager.write_file(file_path, final_code)
|
260
|
+
```
|
261
|
+
|
262
|
+
### Error Context
|
263
|
+
```python
|
264
|
+
# Always provide context in error messages
|
265
|
+
def add_import_with_context(self, import_statement: str, file_context: str) -> None:
|
266
|
+
try:
|
267
|
+
self.import_collector.add_import(import_statement)
|
268
|
+
except Exception as e:
|
269
|
+
raise ImportError(f"Failed to add import '{import_statement}' in {file_context}: {e}")
|
270
|
+
```
|
271
|
+
|
272
|
+
## Common Pitfalls
|
273
|
+
|
274
|
+
1. **Import Leakage**: Not clearing imports between files
|
275
|
+
2. **Path Confusion**: Using absolute paths instead of relative
|
276
|
+
3. **State Mutation**: Modifying context from multiple threads
|
277
|
+
4. **Memory Leaks**: Not cleaning up context after generation
|
278
|
+
|
279
|
+
## Best Practices
|
280
|
+
|
281
|
+
1. **One Context Per Session**: Create new context for each generation
|
282
|
+
2. **Clear Between Files**: Always clear imports between file generations
|
283
|
+
3. **Use Relative Imports**: Convert absolute imports to relative
|
284
|
+
4. **Error Context**: Include file/operation context in errors
|
@@ -274,10 +274,10 @@ class ImportCollector:
|
|
274
274
|
is_core_module_to_be_absolute = True
|
275
275
|
|
276
276
|
if is_core_module_to_be_absolute:
|
277
|
-
import_statement = f"from {module_name} import {
|
277
|
+
import_statement = f"from {module_name} import {', '.join(names)}"
|
278
278
|
standard_import_lines.append(import_statement)
|
279
279
|
elif is_stdlib_module:
|
280
|
-
import_statement = f"from {module_name} import {
|
280
|
+
import_statement = f"from {module_name} import {', '.join(names)}"
|
281
281
|
standard_import_lines.append(import_statement)
|
282
282
|
elif (
|
283
283
|
current_module_dot_path_to_use
|
@@ -286,13 +286,13 @@ class ImportCollector:
|
|
286
286
|
):
|
287
287
|
try:
|
288
288
|
relative_module = make_relative_import(current_module_dot_path_to_use, module_name)
|
289
|
-
import_statement = f"from {relative_module} import {
|
289
|
+
import_statement = f"from {relative_module} import {', '.join(names)}"
|
290
290
|
standard_import_lines.append(import_statement)
|
291
291
|
except ValueError as e:
|
292
|
-
import_statement = f"from {module_name} import {
|
292
|
+
import_statement = f"from {module_name} import {', '.join(names)}"
|
293
293
|
standard_import_lines.append(import_statement)
|
294
294
|
else:
|
295
|
-
import_statement = f"from {module_name} import {
|
295
|
+
import_statement = f"from {module_name} import {', '.join(names)}"
|
296
296
|
standard_import_lines.append(import_statement)
|
297
297
|
|
298
298
|
plain_import_lines: List[str] = []
|
@@ -331,7 +331,7 @@ class ImportCollector:
|
|
331
331
|
|
332
332
|
for module in stdlib_modules:
|
333
333
|
names = sorted(self.imports[module])
|
334
|
-
statements.append(f"from {module} import {
|
334
|
+
statements.append(f"from {module} import {', '.join(names)}")
|
335
335
|
|
336
336
|
# Then third-party and app imports
|
337
337
|
other_modules = sorted([m for m in self.imports.keys() if not _is_stdlib(m)])
|
@@ -341,7 +341,7 @@ class ImportCollector:
|
|
341
341
|
|
342
342
|
for module in other_modules:
|
343
343
|
names = sorted(self.imports[module])
|
344
|
-
statements.append(f"from {module} import {
|
344
|
+
statements.append(f"from {module} import {', '.join(names)}")
|
345
345
|
|
346
346
|
# Then plain imports
|
347
347
|
if self.plain_imports:
|
@@ -357,7 +357,7 @@ class ImportCollector:
|
|
357
357
|
|
358
358
|
for module in sorted(self.relative_imports.keys()):
|
359
359
|
names = sorted(self.relative_imports[module])
|
360
|
-
statements.append(f"from {module} import {
|
360
|
+
statements.append(f"from {module} import {', '.join(names)}")
|
361
361
|
|
362
362
|
return "\n".join(statements)
|
363
363
|
|