pyopenapi-gen 0.20.1__tar.gz → 0.21.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.

Potentially problematic release.


This version of pyopenapi-gen might be problematic. Click here for more details.

Files changed (342) hide show
  1. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/CHANGELOG.md +40 -0
  2. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/PKG-INFO +1 -1
  3. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/coverage.xml +39 -28
  4. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/pyproject.toml +2 -2
  5. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/__init__.py +1 -1
  6. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/utils.py +21 -2
  7. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_utils.py +245 -0
  8. pyopenapi_gen-0.21.0/tests/integration/test_field_mapping_e2e.py +146 -0
  9. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.bandit +0 -0
  10. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.cursor/mcp.json +0 -0
  11. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.cursor/rules/architecture.mdc +0 -0
  12. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.cursor/rules/coding-conventions.mdc +0 -0
  13. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.cursor/rules/project-goal.mdc +0 -0
  14. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.cursor/rules/testing.mdc +0 -0
  15. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/BRANCH_PROTECTION.md +0 -0
  16. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/CLAUDE_CONFIGURATION.md +0 -0
  17. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/CODEOWNERS +0 -0
  18. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/ISSUE_TEMPLATE/bug_report.md +0 -0
  19. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/ISSUE_TEMPLATE/feature_request.md +0 -0
  20. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/dependabot.yml +0 -0
  21. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/ci.yml +0 -0
  22. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/claude-auto-approve.yml +0 -0
  23. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/claude-review-trigger.yml +0 -0
  24. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/claude.yml +0 -0
  25. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/pr-checks.yml +0 -0
  26. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/production-release.yml.backup +0 -0
  27. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/promote-to-staging.yml +0 -0
  28. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/semantic-release.yml +0 -0
  29. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/staging-publish.yml +0 -0
  30. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.github/workflows/testpypi-publish.yml +0 -0
  31. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.gitignore +0 -0
  32. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.python-version +0 -0
  33. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/.vscode/settings.json +0 -0
  34. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/CLAUDE.md +0 -0
  35. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/CONTRIBUTING.md +0 -0
  36. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/LICENSE +0 -0
  37. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/Makefile +0 -0
  38. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/README.md +0 -0
  39. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/README.md +0 -0
  40. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/architecture.md +0 -0
  41. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/endpoint_visitor.md +0 -0
  42. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/helpers.md +0 -0
  43. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/ir_models.md +0 -0
  44. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/line_writer.md +0 -0
  45. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/loader.md +0 -0
  46. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/model_visitor.md +0 -0
  47. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/release-automation.md +0 -0
  48. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/render_context.md +0 -0
  49. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/docs/unified_type_resolution.md +0 -0
  50. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/input/business_swagger.json +0 -0
  51. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/input/minimal_swagger.json +0 -0
  52. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/input/minimal_syntax_test.json +0 -0
  53. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/input/test_name_collision_spec.json +0 -0
  54. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/mkdocs.yml +0 -0
  55. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/poetry.lock +0 -0
  56. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/scripts/sync_version_to_init.py +0 -0
  57. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/scripts/validate_version_sync.py +0 -0
  58. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/__main__.py +0 -0
  59. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/cli.py +0 -0
  60. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/context/CLAUDE.md +0 -0
  61. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/context/file_manager.py +0 -0
  62. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/context/import_collector.py +0 -0
  63. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/context/render_context.py +0 -0
  64. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/CLAUDE.md +0 -0
  65. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/__init__.py +0 -0
  66. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/auth/base.py +0 -0
  67. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/auth/plugins.py +0 -0
  68. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/exceptions.py +0 -0
  69. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/http_status_codes.py +0 -0
  70. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/http_transport.py +0 -0
  71. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/__init__.py +0 -0
  72. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/loader.py +0 -0
  73. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/operations/__init__.py +0 -0
  74. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/operations/parser.py +0 -0
  75. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/operations/post_processor.py +0 -0
  76. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/operations/request_body.py +0 -0
  77. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/parameters/__init__.py +0 -0
  78. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/parameters/parser.py +0 -0
  79. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/responses/__init__.py +0 -0
  80. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/responses/parser.py +0 -0
  81. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/schemas/__init__.py +0 -0
  82. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/loader/schemas/extractor.py +0 -0
  83. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/pagination.py +0 -0
  84. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/__init__.py +0 -0
  85. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/__init__.py +0 -0
  86. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/__init__.py +0 -0
  87. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/__init__.py +0 -0
  88. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/cyclic_properties.py +0 -0
  89. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/direct_cycle.py +0 -0
  90. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/existing_schema.py +0 -0
  91. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/list_response.py +0 -0
  92. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/missing_ref.py +0 -0
  93. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/new_schema.py +0 -0
  94. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/helpers/stripped_suffix.py +0 -0
  95. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/ref_resolution/resolve_schema_ref.py +0 -0
  96. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/common/type_parser.py +0 -0
  97. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/context.py +0 -0
  98. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/cycle_helpers.py +0 -0
  99. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/__init__.py +0 -0
  100. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/all_of_parser.py +0 -0
  101. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/any_of_parser.py +0 -0
  102. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/array_items_parser.py +0 -0
  103. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/one_of_parser.py +0 -0
  104. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/keywords/properties_parser.py +0 -0
  105. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/schema_finalizer.py +0 -0
  106. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/schema_parser.py +0 -0
  107. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/transformers/__init__.py +0 -0
  108. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/transformers/inline_enum_extractor.py +0 -0
  109. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/transformers/inline_object_promoter.py +0 -0
  110. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/parsing/unified_cycle_detection.py +0 -0
  111. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/postprocess_manager.py +0 -0
  112. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/schemas.py +0 -0
  113. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/streaming_helpers.py +0 -0
  114. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/telemetry.py +0 -0
  115. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/warning_collector.py +0 -0
  116. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/writers/code_writer.py +0 -0
  117. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/writers/documentation_writer.py +0 -0
  118. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/writers/line_writer.py +0 -0
  119. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core/writers/python_construct_renderer.py +0 -0
  120. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/core_package_template/README.md +0 -0
  121. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emit/models_emitter.py +0 -0
  122. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/CLAUDE.md +0 -0
  123. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/client_emitter.py +0 -0
  124. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/core_emitter.py +0 -0
  125. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/docs_emitter.py +0 -0
  126. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/endpoints_emitter.py +0 -0
  127. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/exceptions_emitter.py +0 -0
  128. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/emitters/models_emitter.py +0 -0
  129. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/generator/CLAUDE.md +0 -0
  130. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/generator/client_generator.py +0 -0
  131. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/CLAUDE.md +0 -0
  132. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/__init__.py +0 -0
  133. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/endpoint_utils.py +0 -0
  134. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_cleaner.py +0 -0
  135. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_helper.py +0 -0
  136. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/__init__.py +0 -0
  137. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/array_resolver.py +0 -0
  138. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/composition_resolver.py +0 -0
  139. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/finalizer.py +0 -0
  140. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/named_resolver.py +0 -0
  141. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/object_resolver.py +0 -0
  142. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/primitive_resolver.py +0 -0
  143. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/type_resolution/resolver.py +0 -0
  144. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/helpers/url_utils.py +0 -0
  145. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/http_types.py +0 -0
  146. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/ir.py +0 -0
  147. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/py.typed +0 -0
  148. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/CLAUDE.md +0 -0
  149. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/__init__.py +0 -0
  150. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/contracts/__init__.py +0 -0
  151. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/contracts/protocols.py +0 -0
  152. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/contracts/types.py +0 -0
  153. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/resolvers/__init__.py +0 -0
  154. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/resolvers/reference_resolver.py +0 -0
  155. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/resolvers/response_resolver.py +0 -0
  156. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/resolvers/schema_resolver.py +0 -0
  157. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/services/__init__.py +0 -0
  158. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/services/type_service.py +0 -0
  159. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/strategies/__init__.py +0 -0
  160. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/types/strategies/response_strategy.py +0 -0
  161. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/CLAUDE.md +0 -0
  162. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/client_visitor.py +0 -0
  163. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/docs_visitor.py +0 -0
  164. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/__init__.py +0 -0
  165. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/endpoint_visitor.py +0 -0
  166. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/__init__.py +0 -0
  167. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/docstring_generator.py +0 -0
  168. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/endpoint_method_generator.py +0 -0
  169. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/overload_generator.py +0 -0
  170. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/request_generator.py +0 -0
  171. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/response_handler_generator.py +0 -0
  172. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/signature_generator.py +0 -0
  173. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/generators/url_args_generator.py +0 -0
  174. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/processors/__init__.py +0 -0
  175. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/processors/import_analyzer.py +0 -0
  176. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/endpoint/processors/parameter_processor.py +0 -0
  177. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/exception_visitor.py +0 -0
  178. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/model/__init__.py +0 -0
  179. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/model/alias_generator.py +0 -0
  180. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/model/dataclass_generator.py +0 -0
  181. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/model/enum_generator.py +0 -0
  182. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/model/model_visitor.py +0 -0
  183. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/src/pyopenapi_gen/visit/visitor.py +0 -0
  184. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/__init__.py +0 -0
  185. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/api/test_programmatic_api.py +0 -0
  186. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/auth/auth_analysis.md +0 -0
  187. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/auth/test_auth_base.py +0 -0
  188. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/auth/test_auth_plugins.py +0 -0
  189. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/cli_analysis.md +0 -0
  190. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/test_cli_backup_diff.py +0 -0
  191. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/test_cli_edge_cases.py +0 -0
  192. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/test_cli_edge_cases_comprehensive.py +0 -0
  193. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/test_cli_internal_utils.py +0 -0
  194. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/cli/test_http_pagination_cli.py +0 -0
  195. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/context_analysis.md +0 -0
  196. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_core_import_path.py +0 -0
  197. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_file_manager.py +0 -0
  198. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_import_collector.py +0 -0
  199. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_render_context.py +0 -0
  200. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_render_context_imports.py +0 -0
  201. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/context/test_render_context_relative_paths.py +0 -0
  202. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/core_analysis.md +0 -0
  203. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/loader/parameters/test_inline_enum_array_params.py +0 -0
  204. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/loader/test_extractor.py +0 -0
  205. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/loader/test_top_level_enum_extraction.py +0 -0
  206. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/helpers_analysis.md +0 -0
  207. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_cyclic_properties.py +0 -0
  208. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_direct_cycle.py +0 -0
  209. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_existing_schema.py +0 -0
  210. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_list_response.py +0 -0
  211. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_missing_ref.py +0 -0
  212. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_new_schema.py +0 -0
  213. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/common/ref_resolution/helpers/test_stripped_suffix.py +0 -0
  214. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/__init__.py +0 -0
  215. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/keywords_analysis.md +0 -0
  216. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/test_all_of_parser.py +0 -0
  217. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/test_any_of_parser.py +0 -0
  218. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/test_array_items_parser.py +0 -0
  219. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/test_one_of_parser.py +0 -0
  220. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/keywords/test_properties_parser.py +0 -0
  221. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/parsing_analysis.md +0 -0
  222. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_context.py +0 -0
  223. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_cycle_detection.py +0 -0
  224. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_cycle_helpers.py +0 -0
  225. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_improved_schema_naming.py +0 -0
  226. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_inline_enum_extractor.py +0 -0
  227. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_inline_object_promoter.py +0 -0
  228. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_logging.py +0 -0
  229. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_ref_resolver.py +0 -0
  230. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_schema_finalizer.py +0 -0
  231. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_schema_parser.py +0 -0
  232. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_schema_parser_list_response.py +0 -0
  233. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/parsing/test_type_parser.py +0 -0
  234. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_dataclass_serialization.py +0 -0
  235. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_detect_circular_imports.py +0 -0
  236. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_edge_cases_integration.py +0 -0
  237. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_edge_cases_systematic.py +0 -0
  238. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_exceptions_module.py +0 -0
  239. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_forward_references.py +0 -0
  240. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_http_transport.py +0 -0
  241. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_import_resolution.py +0 -0
  242. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_ir.py +0 -0
  243. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_ir_schema.py +0 -0
  244. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_loader.py +0 -0
  245. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_loader_extensive.py +0 -0
  246. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_loader_invalid_refs.py +0 -0
  247. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_loader_malformed.py +0 -0
  248. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_loader_media_types.py +0 -0
  249. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_pagination.py +0 -0
  250. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_parsing_context.py +0 -0
  251. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_protocol_defaults.py +0 -0
  252. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_schema_parser_specific_case.py +0 -0
  253. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_schemas.py +0 -0
  254. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_simple_self_ref_check.py +0 -0
  255. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_streaming_helpers.py +0 -0
  256. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_telemetry.py +0 -0
  257. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_telemetry_client.py +0 -0
  258. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/test_warning_collector.py +0 -0
  259. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/writers/test_code_writer.py +0 -0
  260. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/writers/test_documentation_writer.py +0 -0
  261. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/writers/test_line_writer.py +0 -0
  262. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/writers/test_python_construct_renderer_json_wizard.py +0 -0
  263. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/core/writers/writers_analysis.md +0 -0
  264. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/emitters_analysis.md +0 -0
  265. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_client_emitter.py +0 -0
  266. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_docs_emitter.py +0 -0
  267. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_duplicate_operations.py +0 -0
  268. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_endpoints_emitter.py +0 -0
  269. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_exceptions_emitter.py +0 -0
  270. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_list_response_generation.py +0 -0
  271. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/emitters/test_models_emitter.py +0 -0
  272. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/end_to_end/test_dataclass_serialization_e2e.py +0 -0
  273. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/examples/test_developer_experience_demo.py +0 -0
  274. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation/generation_analysis.md +0 -0
  275. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation/test_external_core_package.py +0 -0
  276. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation_issues/specs/minimal_addmessage_like.json +0 -0
  277. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation_issues/test_addmessage_like_issues.py +0 -0
  278. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation_issues/test_agent_include_parameter_typing.py +0 -0
  279. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation_issues/test_message_batch_response_issue.py +0 -0
  280. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/generation_issues/test_overload_naming_issues.py +0 -0
  281. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/helpers_analysis.md +0 -0
  282. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_array_resolver.py +0 -0
  283. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_endpoint_utils.py +0 -0
  284. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_endpoint_utils_extended.py +0 -0
  285. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_get_endpoint_return_types.py +0 -0
  286. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_named_resolver.py +0 -0
  287. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_named_type_resolver.py +0 -0
  288. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_object_resolver.py +0 -0
  289. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_put_endpoint_return_types.py +0 -0
  290. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_type_cleaner.py +0 -0
  291. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_type_helper.py +0 -0
  292. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_url_utils.py +0 -0
  293. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/helpers/test_utils_helpers.py +0 -0
  294. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integration/test_generated_code_structure.py +0 -0
  295. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integrations/integrations_analysis.md +0 -0
  296. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integrations/test_business_swagger_message_type.py +0 -0
  297. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integrations/test_end_to_end_business_swagger.py +0 -0
  298. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integrations/test_end_to_end_petstore.py +0 -0
  299. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/integrations/test_name_collisions.py +0 -0
  300. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/specs/response_unwrapping_spec.yaml +0 -0
  301. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/test_analysis_overview.md +0 -0
  302. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/test_init.py +0 -0
  303. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/__init__.py +0 -0
  304. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_business_swagger_integration.py +0 -0
  305. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_contracts_types.py +0 -0
  306. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_missing_imports_bug.py +0 -0
  307. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_reference_resolver.py +0 -0
  308. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_response_resolver.py +0 -0
  309. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_response_strategy.py +0 -0
  310. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_response_strategy_simplified.py +0 -0
  311. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_schema_resolver.py +0 -0
  312. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_schema_resolver_enums.py +0 -0
  313. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/types/test_type_service.py +0 -0
  314. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/__init__.py +0 -0
  315. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/__init__.py +0 -0
  316. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/__init__.py +0 -0
  317. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/generators_analysis.md +0 -0
  318. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_dataclass_integration.py +0 -0
  319. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_docstring_generator.py +0 -0
  320. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_endpoint_method_generator.py +0 -0
  321. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_match_case_response.py +0 -0
  322. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_overload_generator.py +0 -0
  323. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_request_generator.py +0 -0
  324. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_response_handler_generator.py +0 -0
  325. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_response_handler_generator_strategy.py +0 -0
  326. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_signature_generator.py +0 -0
  327. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/generators/test_url_args_generator.py +0 -0
  328. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/processors/__init__.py +0 -0
  329. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/processors/test_import_analyzer.py +0 -0
  330. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/processors/test_import_analyzer.py.bak +0 -0
  331. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/processors/test_parameter_processor.py +0 -0
  332. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/endpoint/test_endpoint_visitor.py +0 -0
  333. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/__init__.py +0 -0
  334. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_alias_generator.py +0 -0
  335. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_dataclass_generator.py +0 -0
  336. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_dataclass_generator_json_wizard.py +0 -0
  337. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_enum_generator.py +0 -0
  338. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_json_value_integration.py +0 -0
  339. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/model/test_json_value_wrapper.py +0 -0
  340. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/test_client_visitor.py +0 -0
  341. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/test_model_visitor.py +0 -0
  342. {pyopenapi_gen-0.20.1 → pyopenapi_gen-0.21.0}/tests/visit/test_visitor.py +0 -0
@@ -1,6 +1,46 @@
1
1
  # CHANGELOG
2
2
 
3
3
 
4
+ ## v0.21.0 (2025-10-23)
5
+
6
+ ### Bug Fixes
7
+
8
+ - **serialization**: Respect BaseSchema field mappings in DataclassSerializer
9
+ ([`ef5d365`](https://github.com/mindhiveoy/pyopenapi_gen/commit/ef5d3656008417bbae17e6370e33e7b0c12cefd6))
10
+
11
+ BREAKING CHANGE: DataclassSerializer now correctly maps Python snake_case field names to API
12
+ camelCase field names when serializing BaseSchema instances.
13
+
14
+ Problem: DataclassSerializer.serialize() was using Python field names (snake_case) directly as
15
+ dictionary keys, ignoring the field name mappings defined in
16
+ BaseSchema.Meta.key_transform_with_load. This caused API requests to send incorrect field names,
17
+ breaking communication with camelCase APIs.
18
+
19
+ Solution: Modified DataclassSerializer._serialize_with_tracking() to detect BaseSchema instances and
20
+ use their to_dict() method, which properly handles field name mapping. Falls back to original
21
+ behavior for plain dataclasses to maintain backwards compatibility.
22
+
23
+ Changes: - Updated DataclassSerializer._serialize_with_tracking() in core/utils.py - Added 5
24
+ comprehensive unit tests for field mapping scenarios - Added 2 end-to-end integration tests with
25
+ business_swagger.json - All existing tests pass with 88.42% coverage (exceeds 85% requirement)
26
+
27
+ Example: Before: {"data_source_id": "123"} ❌
28
+
29
+ After: {"dataSourceId": "123"} ✅
30
+
31
+ Fixes critical bug affecting all generated clients with camelCase APIs.
32
+
33
+ ### Chores
34
+
35
+ - **release**: Sync __init__.py version [skip ci]
36
+ ([`446d496`](https://github.com/mindhiveoy/pyopenapi_gen/commit/446d4963a1e8428da7b6476088104aac599dae8f))
37
+
38
+ ### Breaking Changes
39
+
40
+ - **serialization**: Dataclassserializer now correctly maps Python snake_case field names to API
41
+ camelCase field names when serializing BaseSchema instances.
42
+
43
+
4
44
  ## v0.20.1 (2025-10-21)
5
45
 
6
46
  ### Bug Fixes
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyopenapi-gen
3
- Version: 0.20.1
3
+ Version: 0.21.0
4
4
  Summary: Modern, async-first Python client generator for OpenAPI specifications with advanced cycle detection and unified type resolution
5
5
  Project-URL: Homepage, https://github.com/your-org/pyopenapi-gen
6
6
  Project-URL: Documentation, https://github.com/your-org/pyopenapi-gen/blob/main/README.md
@@ -1,5 +1,5 @@
1
1
  <?xml version="1.0" ?>
2
- <coverage version="7.10.7" timestamp="1761058806878" lines-valid="6507" lines-covered="5752" line-rate="0.884" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
2
+ <coverage version="7.10.7" timestamp="1761233680435" lines-valid="6518" lines-covered="5763" line-rate="0.8842" branches-covered="0" branches-valid="0" branch-rate="0" complexity="0">
3
3
  <!-- Generated by coverage.py: https://coverage.readthedocs.io/en/7.10.7 -->
4
4
  <!-- Based on https://raw.githubusercontent.com/cobertura/web/master/htdocs/xml/coverage-04.dtd -->
5
5
  <sources>
@@ -652,7 +652,7 @@
652
652
  </class>
653
653
  </classes>
654
654
  </package>
655
- <package name="pyopenapi_gen.core" line-rate="0.8327" branch-rate="0" complexity="0">
655
+ <package name="pyopenapi_gen.core" line-rate="0.836" branch-rate="0" complexity="0">
656
656
  <classes>
657
657
  <class name="__init__.py" filename="pyopenapi_gen/core/__init__.py" complexity="0" line-rate="1" branch-rate="0">
658
658
  <methods/>
@@ -1053,7 +1053,7 @@
1053
1053
  <line number="69" hits="1"/>
1054
1054
  </lines>
1055
1055
  </class>
1056
- <class name="utils.py" filename="pyopenapi_gen/core/utils.py" complexity="0" line-rate="0.9353" branch-rate="0">
1056
+ <class name="utils.py" filename="pyopenapi_gen/core/utils.py" complexity="0" line-rate="0.9392" branch-rate="0">
1057
1057
  <methods/>
1058
1058
  <lines>
1059
1059
  <line number="6" hits="1"/>
@@ -1173,59 +1173,70 @@
1173
1173
  <line number="313" hits="1"/>
1174
1174
  <line number="320" hits="1"/>
1175
1175
  <line number="321" hits="1"/>
1176
- <line number="339" hits="1"/>
1177
1176
  <line number="341" hits="1"/>
1178
- <line number="342" hits="1"/>
1177
+ <line number="343" hits="1"/>
1179
1178
  <line number="344" hits="1"/>
1180
- <line number="347" hits="1"/>
1181
- <line number="348" hits="1"/>
1182
- <line number="351" hits="1"/>
1183
- <line number="352" hits="1"/>
1179
+ <line number="346" hits="1"/>
1180
+ <line number="349" hits="1"/>
1181
+ <line number="350" hits="1"/>
1182
+ <line number="353" hits="1"/>
1184
1183
  <line number="354" hits="1"/>
1185
- <line number="355" hits="1"/>
1186
- <line number="356" hits="0"/>
1187
- <line number="359" hits="1"/>
1188
- <line number="360" hits="1"/>
1189
- <line number="363" hits="1"/>
1190
- <line number="364" hits="1"/>
1191
- <line number="367" hits="1"/>
1192
- <line number="368" hits="1"/>
1193
- <line number="369" hits="1"/>
1184
+ <line number="356" hits="1"/>
1185
+ <line number="357" hits="1"/>
1186
+ <line number="358" hits="0"/>
1187
+ <line number="361" hits="1"/>
1188
+ <line number="362" hits="1"/>
1189
+ <line number="365" hits="1"/>
1190
+ <line number="366" hits="1"/>
1194
1191
  <line number="370" hits="1"/>
1195
1192
  <line number="371" hits="1"/>
1196
1193
  <line number="372" hits="1"/>
1197
1194
  <line number="374" hits="1"/>
1198
- <line number="375" hits="1"/>
1199
1195
  <line number="376" hits="1"/>
1200
1196
  <line number="377" hits="1"/>
1201
1197
  <line number="378" hits="1"/>
1198
+ <line number="379" hits="1"/>
1202
1199
  <line number="380" hits="1"/>
1200
+ <line number="381" hits="1"/>
1203
1201
  <line number="383" hits="1"/>
1204
- <line number="384" hits="1"/>
1202
+ <line number="386" hits="1"/>
1205
1203
  <line number="387" hits="1"/>
1206
1204
  <line number="388" hits="1"/>
1207
1205
  <line number="389" hits="1"/>
1208
1206
  <line number="390" hits="1"/>
1209
1207
  <line number="391" hits="1"/>
1210
- <line number="392" hits="1"/>
1211
1208
  <line number="393" hits="1"/>
1209
+ <line number="394" hits="1"/>
1210
+ <line number="395" hits="1"/>
1212
1211
  <line number="396" hits="1"/>
1213
1212
  <line number="397" hits="1"/>
1214
- <line number="400" hits="1"/>
1213
+ <line number="399" hits="1"/>
1215
1214
  <line number="402" hits="1"/>
1216
1215
  <line number="403" hits="1"/>
1217
- <line number="404" hits="1"/>
1218
- <line number="405" hits="1"/>
1219
1216
  <line number="406" hits="1"/>
1220
1217
  <line number="407" hits="1"/>
1221
1218
  <line number="408" hits="1"/>
1222
1219
  <line number="409" hits="1"/>
1223
1220
  <line number="410" hits="1"/>
1224
1221
  <line number="411" hits="1"/>
1225
- <line number="413" hits="1"/>
1226
- <line number="416" hits="0"/>
1227
- <line number="417" hits="0"/>
1228
- <line number="419" hits="0"/>
1222
+ <line number="412" hits="1"/>
1223
+ <line number="415" hits="1"/>
1224
+ <line number="416" hits="1"/>
1225
+ <line number="419" hits="1"/>
1226
+ <line number="421" hits="1"/>
1227
+ <line number="422" hits="1"/>
1228
+ <line number="423" hits="1"/>
1229
+ <line number="424" hits="1"/>
1230
+ <line number="425" hits="1"/>
1231
+ <line number="426" hits="1"/>
1232
+ <line number="427" hits="1"/>
1233
+ <line number="428" hits="1"/>
1234
+ <line number="429" hits="1"/>
1235
+ <line number="430" hits="1"/>
1236
+ <line number="432" hits="1"/>
1237
+ <line number="435" hits="0"/>
1238
+ <line number="436" hits="0"/>
1239
+ <line number="438" hits="0"/>
1229
1240
  </lines>
1230
1241
  </class>
1231
1242
  <class name="warning_collector.py" filename="pyopenapi_gen/core/warning_collector.py" complexity="0" line-rate="1" branch-rate="0">
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "pyopenapi-gen"
7
- version = "0.20.1"
7
+ version = "0.21.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" }]
@@ -140,7 +140,7 @@ pyopenapi-gen = "pyopenapi_gen.cli:app"
140
140
 
141
141
  [tool.commitizen]
142
142
  name = "cz_conventional_commits"
143
- version = "0.20.1"
143
+ version = "0.21.0"
144
144
  version_files = [
145
145
  "pyproject.toml:version",
146
146
  "src/pyopenapi_gen/__init__.py:__version__"
@@ -50,7 +50,7 @@ __all__ = [
50
50
  ]
51
51
 
52
52
  # Semantic version of the generator core – automatically managed by semantic-release.
53
- __version__: str = "0.20.1"
53
+ __version__: str = "0.21.0"
54
54
 
55
55
  # ---------------------------------------------------------------------------
56
56
  # Lazy-loading and autocompletion support (This part remains)
@@ -328,10 +328,12 @@ class DataclassSerializer:
328
328
  The serialized object with dataclasses converted to dictionaries.
329
329
 
330
330
  Handles:
331
- - Dataclass instances: Converted to dictionaries
331
+ - BaseSchema instances: Uses to_dict() method with field name mapping (e.g., snake_case -> camelCase)
332
+ - Regular dataclass instances: Converted to dictionaries using field names
332
333
  - Lists: Recursively serialize each item
333
334
  - Dictionaries: Recursively serialize values
334
335
  - datetime: Convert to ISO format string
336
+ - Enums: Convert to their value
335
337
  - Primitives: Return unchanged
336
338
  - None values: Excluded from output
337
339
  """
@@ -363,7 +365,24 @@ class DataclassSerializer:
363
365
  if isinstance(obj, Enum) and not isinstance(obj, type):
364
366
  return obj.value
365
367
 
366
- # Handle dataclass instances
368
+ # Handle BaseSchema instances (respects field name mappings)
369
+ # Check for BaseSchema by looking for both to_dict and _get_field_mappings methods
370
+ if hasattr(obj, "to_dict") and hasattr(obj, "_get_field_mappings") and callable(obj.to_dict):
371
+ visited.add(obj_id)
372
+ try:
373
+ # Use BaseSchema's to_dict() which handles field name mapping
374
+ result_dict = obj.to_dict(exclude_none=True)
375
+ # Recursively serialize nested objects in the result
376
+ serialized_result = {}
377
+ for key, value in result_dict.items():
378
+ serialized_value = DataclassSerializer._serialize_with_tracking(value, visited)
379
+ if serialized_value is not None:
380
+ serialized_result[key] = serialized_value
381
+ return serialized_result
382
+ finally:
383
+ visited.discard(obj_id)
384
+
385
+ # Handle regular dataclass instances (no field mapping)
367
386
  if dataclasses.is_dataclass(obj) and not isinstance(obj, type):
368
387
  visited.add(obj_id)
369
388
  try:
@@ -357,3 +357,248 @@ def test_import_collector_sibling_directory_import() -> None:
357
357
  assert "from ..models.bar import Baz" in statements
358
358
  for stmt in statements:
359
359
  assert "/" not in stmt, f"Slash found in import statement: {stmt}"
360
+
361
+
362
+ # DataclassSerializer Tests
363
+
364
+
365
+ def test_dataclass_serializer__baseschema_with_mappings__uses_api_field_names() -> None:
366
+ """Test DataclassSerializer respects BaseSchema field name mappings.
367
+
368
+ Scenario:
369
+ - Create a BaseSchema dataclass with field mappings (snake_case -> camelCase)
370
+ - Serialize the instance using DataclassSerializer.serialize()
371
+
372
+ Expected Outcome:
373
+ - The serialized dictionary should use API field names (camelCase)
374
+ - Should not use Python field names (snake_case)
375
+ """
376
+ # Arrange
377
+ from dataclasses import dataclass
378
+
379
+ from pyopenapi_gen.core.schemas import BaseSchema
380
+ from pyopenapi_gen.core.utils import DataclassSerializer
381
+
382
+ @dataclass
383
+ class DocumentUpdate(BaseSchema):
384
+ """Test schema with field mappings."""
385
+
386
+ data_source_id: str
387
+ mime_type: str | None = None
388
+ last_modified: str | None = None
389
+
390
+ class Meta:
391
+ """Field mappings."""
392
+
393
+ key_transform_with_load = {
394
+ "dataSourceId": "data_source_id",
395
+ "mimeType": "mime_type",
396
+ "lastModified": "last_modified",
397
+ }
398
+
399
+ obj = DocumentUpdate(data_source_id="source-123", mime_type="text/html", last_modified="2024-10-23")
400
+
401
+ # Act
402
+ result = DataclassSerializer.serialize(obj)
403
+
404
+ # Assert
405
+ assert isinstance(result, dict)
406
+ assert "dataSourceId" in result # camelCase (API name)
407
+ assert "mimeType" in result
408
+ assert "lastModified" in result
409
+ assert "data_source_id" not in result # snake_case (Python name) should NOT be present
410
+ assert "mime_type" not in result
411
+ assert "last_modified" not in result
412
+ assert result["dataSourceId"] == "source-123"
413
+ assert result["mimeType"] == "text/html"
414
+ assert result["lastModified"] == "2024-10-23"
415
+
416
+
417
+ def test_dataclass_serializer__nested_baseschema__maps_recursively() -> None:
418
+ """Test DataclassSerializer handles nested BaseSchema instances with field mappings.
419
+
420
+ Scenario:
421
+ - Create nested BaseSchema dataclasses with field mappings
422
+ - Serialize the parent instance
423
+
424
+ Expected Outcome:
425
+ - Both parent and nested objects should use API field names
426
+ - Nested field mappings should be respected recursively
427
+ """
428
+ # Arrange
429
+ from dataclasses import dataclass
430
+
431
+ from pyopenapi_gen.core.schemas import BaseSchema
432
+ from pyopenapi_gen.core.utils import DataclassSerializer
433
+
434
+ @dataclass
435
+ class Address(BaseSchema):
436
+ """Nested schema with field mappings."""
437
+
438
+ street_name: str
439
+ postal_code: str
440
+
441
+ class Meta:
442
+ """Field mappings."""
443
+
444
+ key_transform_with_load = {"streetName": "street_name", "postalCode": "postal_code"}
445
+
446
+ @dataclass
447
+ class User(BaseSchema):
448
+ """Parent schema with field mappings."""
449
+
450
+ user_id: str
451
+ full_name: str
452
+ home_address: Address
453
+
454
+ class Meta:
455
+ """Field mappings."""
456
+
457
+ key_transform_with_load = {
458
+ "userId": "user_id",
459
+ "fullName": "full_name",
460
+ "homeAddress": "home_address",
461
+ }
462
+
463
+ address = Address(street_name="Main St", postal_code="12345")
464
+ user = User(user_id="user-123", full_name="John Doe", home_address=address)
465
+
466
+ # Act
467
+ result = DataclassSerializer.serialize(user)
468
+
469
+ # Assert
470
+ assert isinstance(result, dict)
471
+ assert "userId" in result
472
+ assert "fullName" in result
473
+ assert "homeAddress" in result
474
+ assert isinstance(result["homeAddress"], dict)
475
+ assert "streetName" in result["homeAddress"]
476
+ assert "postalCode" in result["homeAddress"]
477
+ assert result["userId"] == "user-123"
478
+ assert result["homeAddress"]["streetName"] == "Main St"
479
+
480
+
481
+ def test_dataclass_serializer__plain_dataclass__still_works() -> None:
482
+ """Test DataclassSerializer backwards compatibility with plain dataclasses.
483
+
484
+ Scenario:
485
+ - Create a plain dataclass (not BaseSchema)
486
+ - Serialize the instance
487
+
488
+ Expected Outcome:
489
+ - Should use field.name directly (no field mapping)
490
+ - Backwards compatibility maintained
491
+ """
492
+ # Arrange
493
+ from dataclasses import dataclass
494
+
495
+ from pyopenapi_gen.core.utils import DataclassSerializer
496
+
497
+ @dataclass
498
+ class PlainModel:
499
+ """Plain dataclass without BaseSchema."""
500
+
501
+ field_one: str
502
+ field_two: int
503
+
504
+ obj = PlainModel(field_one="value", field_two=42)
505
+
506
+ # Act
507
+ result = DataclassSerializer.serialize(obj)
508
+
509
+ # Assert
510
+ assert isinstance(result, dict)
511
+ assert "field_one" in result
512
+ assert "field_two" in result
513
+ assert result["field_one"] == "value"
514
+ assert result["field_two"] == 42
515
+
516
+
517
+ def test_dataclass_serializer__exclude_none_handling() -> None:
518
+ """Test DataclassSerializer excludes None values when using BaseSchema.
519
+
520
+ Scenario:
521
+ - Create a BaseSchema instance with some None values
522
+ - Serialize the instance
523
+
524
+ Expected Outcome:
525
+ - None values should be excluded from the result
526
+ - Non-None values should be present with correct field names
527
+ """
528
+ # Arrange
529
+ from dataclasses import dataclass
530
+
531
+ from pyopenapi_gen.core.schemas import BaseSchema
532
+ from pyopenapi_gen.core.utils import DataclassSerializer
533
+
534
+ @dataclass
535
+ class OptionalFields(BaseSchema):
536
+ """Schema with optional fields."""
537
+
538
+ required_field: str
539
+ optional_field: str | None = None
540
+ another_optional: str | None = None
541
+
542
+ class Meta:
543
+ """Field mappings."""
544
+
545
+ key_transform_with_load = {
546
+ "requiredField": "required_field",
547
+ "optionalField": "optional_field",
548
+ "anotherOptional": "another_optional",
549
+ }
550
+
551
+ obj = OptionalFields(required_field="present", optional_field=None, another_optional=None)
552
+
553
+ # Act
554
+ result = DataclassSerializer.serialize(obj)
555
+
556
+ # Assert
557
+ assert isinstance(result, dict)
558
+ assert "requiredField" in result
559
+ assert "optionalField" not in result # None values excluded
560
+ assert "anotherOptional" not in result
561
+ assert result["requiredField"] == "present"
562
+
563
+
564
+ def test_dataclass_serializer__list_of_baseschema__maps_all_items() -> None:
565
+ """Test DataclassSerializer handles lists of BaseSchema instances.
566
+
567
+ Scenario:
568
+ - Create a list of BaseSchema instances with field mappings
569
+ - Serialize the list
570
+
571
+ Expected Outcome:
572
+ - Each item in the list should have field names mapped
573
+ - All items should use API field names
574
+ """
575
+ # Arrange
576
+ from dataclasses import dataclass
577
+
578
+ from pyopenapi_gen.core.schemas import BaseSchema
579
+ from pyopenapi_gen.core.utils import DataclassSerializer
580
+
581
+ @dataclass
582
+ class Item(BaseSchema):
583
+ """Schema with field mappings."""
584
+
585
+ item_id: str
586
+ item_name: str
587
+
588
+ class Meta:
589
+ """Field mappings."""
590
+
591
+ key_transform_with_load = {"itemId": "item_id", "itemName": "item_name"}
592
+
593
+ items = [Item(item_id="1", item_name="First"), Item(item_id="2", item_name="Second")]
594
+
595
+ # Act
596
+ result = DataclassSerializer.serialize(items)
597
+
598
+ # Assert
599
+ assert isinstance(result, list)
600
+ assert len(result) == 2
601
+ assert all("itemId" in item for item in result)
602
+ assert all("itemName" in item for item in result)
603
+ assert result[0]["itemId"] == "1"
604
+ assert result[1]["itemName"] == "Second"
@@ -0,0 +1,146 @@
1
+ """Integration test for field name mapping in generated clients.
2
+
3
+ Tests that the DataclassSerializer correctly maps Python snake_case field names
4
+ to API camelCase field names when serializing request bodies.
5
+ """
6
+
7
+ import tempfile
8
+ from pathlib import Path
9
+
10
+ import pytest
11
+
12
+ from pyopenapi_gen import generate_client
13
+
14
+
15
+ def test_field_mapping__business_swagger_updateDocument__serializes_to_camelCase() -> None:
16
+ """End-to-end test for field mapping with business_swagger.json.
17
+
18
+ Scenario:
19
+ - Generate client from business_swagger.json
20
+ - Import DocumentUpdate model from generated client
21
+ - Create instance with snake_case attributes
22
+ - Serialize using DataclassSerializer
23
+ - Verify output uses camelCase API field names
24
+
25
+ Expected Outcome:
26
+ - Generated code should include field mappings in Meta class
27
+ - DataclassSerializer should use camelCase keys (not snake_case)
28
+ - Validates the fix for the field mapping bug
29
+ """
30
+ # Arrange - Generate client in temporary directory
31
+ spec_path = "input/business_swagger.json"
32
+ with tempfile.TemporaryDirectory() as tmpdir:
33
+ project_root = Path(tmpdir)
34
+
35
+ # Act - Generate client
36
+ generate_client(
37
+ spec_path=spec_path,
38
+ project_root=str(project_root),
39
+ output_package="businessapi",
40
+ force=True,
41
+ no_postprocess=True, # Skip formatting for speed
42
+ )
43
+
44
+ # Import generated model dynamically
45
+ import sys
46
+
47
+ sys.path.insert(0, str(project_root))
48
+ from businessapi.core.utils import DataclassSerializer
49
+ from businessapi.models.document_update import DocumentUpdate
50
+
51
+ # Create instance with snake_case attributes
52
+ doc_update = DocumentUpdate(
53
+ url="https://example.com/doc",
54
+ data_source_id="source-123",
55
+ mime_type="text/html",
56
+ last_modified="2024-10-23T12:00:00Z",
57
+ )
58
+
59
+ # Act - Serialize using DataclassSerializer
60
+ result = DataclassSerializer.serialize(doc_update)
61
+
62
+ # Assert - Should use camelCase API field names
63
+ assert isinstance(result, dict)
64
+
65
+ # Check that camelCase keys are present
66
+ assert "dataSourceId" in result, "Should use camelCase 'dataSourceId' (API field name)"
67
+ assert "mimeType" in result, "Should use camelCase 'mimeType' (API field name)"
68
+ assert "lastModified" in result, "Should use camelCase 'lastModified' (API field name)"
69
+
70
+ # Check that snake_case keys are NOT present
71
+ assert "data_source_id" not in result, "Should NOT use snake_case 'data_source_id' (Python field name)"
72
+ assert "mime_type" not in result, "Should NOT use snake_case 'mime_type' (Python field name)"
73
+ assert "last_modified" not in result, "Should NOT use snake_case 'last_modified' (Python field name)"
74
+
75
+ # Verify values are correct
76
+ assert result["dataSourceId"] == "source-123"
77
+ assert result["mimeType"] == "text/html"
78
+ assert result["lastModified"] == "2024-10-23T12:00:00Z"
79
+
80
+ # Cleanup
81
+ sys.path.remove(str(project_root))
82
+
83
+
84
+ def test_field_mapping__roundtrip__preserves_data() -> None:
85
+ """Test that field mapping works correctly in both directions.
86
+
87
+ Scenario:
88
+ - Generate client from business_swagger.json
89
+ - Create DocumentUpdate from dict with camelCase keys (API response)
90
+ - Serialize back to dict
91
+ - Verify field names are preserved
92
+
93
+ Expected Outcome:
94
+ - from_dict should accept camelCase and map to snake_case attributes
95
+ - DataclassSerializer should map snake_case attributes back to camelCase
96
+ - Data should be preserved through the roundtrip
97
+ """
98
+ # Arrange - Generate client in temporary directory
99
+ spec_path = "input/business_swagger.json"
100
+ with tempfile.TemporaryDirectory() as tmpdir:
101
+ project_root = Path(tmpdir)
102
+
103
+ # Generate client
104
+ generate_client(
105
+ spec_path=spec_path,
106
+ project_root=str(project_root),
107
+ output_package="businessapi",
108
+ force=True,
109
+ no_postprocess=True, # Skip formatting for speed
110
+ )
111
+
112
+ # Import generated model dynamically
113
+ import sys
114
+
115
+ sys.path.insert(0, str(project_root))
116
+ from businessapi.core.utils import DataclassSerializer
117
+ from businessapi.models.document_update import DocumentUpdate
118
+
119
+ # Act - Create from API response (camelCase)
120
+ api_response = {
121
+ "url": "https://example.com/doc",
122
+ "dataSourceId": "source-456",
123
+ "mimeType": "application/json",
124
+ "lastModified": "2024-10-23T15:30:00Z",
125
+ }
126
+ doc_update = DocumentUpdate.from_dict(api_response)
127
+
128
+ # Verify attributes are accessible via snake_case
129
+ assert doc_update.data_source_id == "source-456"
130
+ assert doc_update.mime_type == "application/json"
131
+ assert doc_update.last_modified == "2024-10-23T15:30:00Z"
132
+
133
+ # Act - Serialize back (should produce camelCase)
134
+ result = DataclassSerializer.serialize(doc_update)
135
+
136
+ # Assert - Should match original API response format
137
+ assert result["dataSourceId"] == "source-456"
138
+ assert result["mimeType"] == "application/json"
139
+ assert result["lastModified"] == "2024-10-23T15:30:00Z"
140
+
141
+ # Cleanup
142
+ sys.path.remove(str(project_root))
143
+
144
+
145
+ if __name__ == "__main__":
146
+ pytest.main([__file__, "-v"])
File without changes