Skip to content

Conversation

@dougborg
Copy link

Closes #79

Summary

Adds end-to-end OpenAPI 3.1 support: version detection, dedicated 3.0 & 3.1 parsers, unified model & service code generation, and extensive test coverage.

Key Changes

  • Version detection utility + separate OpenAPI 3.0 / 3.1 parser modules
  • Model generator enhancements: refs, composite schemas (allOf / oneOf / anyOf), DataType enums, self-references, import aggregation fix for allOf
  • Service generator updates: multi-version media/response handling and request body resolution
  • Generalized generator & api_config for 3.0+ (model_dump usage, shared unions)
  • Unified core model unions (Operation, PathItem, Schema) enabling cross-version typing
  • New comprehensive test suites:
    • Completeness & schema feature coverage for 3.1
    • Negative spec tests (validation & unsupported features)
    • Swagger Petstore 3.0 & 3.1 regression fixtures
    • Edge cases (self-references, composites, imports)
  • Tooling: dependency and typing improvements, test fixture additions

Test Status

poetry run pytest -q → 232 passed, 11 xfailed (intentional skips for unsupported 3.1 features not yet implemented)

Follow-ups (separate PRs)

Backward Compatibility

No breaking changes for OpenAPI 3.0 users; 3.1 is auto-detected and handled transparently.

Feedback welcome.

Copilot AI review requested due to automatic review settings August 10, 2025 16:53
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR introduces comprehensive OpenAPI 3.1 support with version detection, dedicated parsers for both 3.0 and 3.1, unified code generation, and extensive test coverage for new features and backward compatibility validation.

Key changes include:

  • Implemented version detection utility with separate parser modules for OpenAPI 3.0/3.1
  • Enhanced model and service generators with improved schema handling (refs, composites, DataType enums)
  • Added comprehensive test suites covering feature completeness, edge cases, and regression testing with Swagger Petstore specs
  • Updated core functionality to use unified model unions enabling cross-version typing

Reviewed Changes

Copilot reviewed 44 out of 47 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
tests/test_version_detector_edges.py Tests version detection edge cases and error handling
tests/test_swagger_petstore_31.py Swagger Petstore 3.1 regression tests and code generation validation
tests/test_swagger_petstore_30.py Swagger Petstore 3.0 regression tests for backward compatibility
tests/test_service_generator_edges.py Edge case tests for service generator functionality
tests/test_openapi_31_*.py Comprehensive OpenAPI 3.1 feature coverage and completeness testing
tests/test_openapi_30.py OpenAPI 3.0 specific functionality tests
tests/test_model_generator_edges.py Edge case tests for model generator type conversion
Various test data files Test fixtures for OpenAPI 3.1 specifications and Swagger Petstore examples
src/openapi_python_generator/version_detector.py Version detection utility for routing to appropriate parsers
src/openapi_python_generator/parsers/openapi_31.py OpenAPI 3.1 specific parser implementation

},
}

with pytest.raises(Exception): # Should fail to parse
Copy link

Copilot AI Aug 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a bare Exception catch is too broad. Consider catching more specific exceptions like ValidationError or pydantic.ValidationError to make the test more precise and meaningful.

Suggested change
with pytest.raises(Exception): # Should fail to parse
with pytest.raises(ValidationError): # Should fail to parse

Copilot uses AI. Check for mistakes.
},
}

with pytest.raises(Exception): # Should fail to parse
Copy link

Copilot AI Aug 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using a bare Exception catch is too broad. Consider catching more specific exceptions like ValidationError or pydantic.ValidationError to make the test more precise and meaningful.

Suggested change
with pytest.raises(Exception): # Should fail to parse
with pytest.raises(ValidationError): # Should fail to parse

Copilot uses AI. Check for mistakes.
def test_type_converter_unknown_list_first_type_fallback():
# Invalid enum value in list should raise ValidationError (spec invalid)
import pydantic
with pytest.raises(pydantic.ValidationError): # type: ignore[attr-defined]
Copy link

Copilot AI Aug 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The type: ignore comment suggests an import issue. Consider importing ValidationError directly from pydantic at the top of the file instead of using pydantic.ValidationError to avoid the type checker warning.

Suggested change
with pytest.raises(pydantic.ValidationError): # type: ignore[attr-defined]
with pytest.raises(ValidationError):

Copilot uses AI. Check for mistakes.
Doug Borg added 5 commits August 10, 2025 10:59
- Merge path-level parameters into operations
- Add default tag fallback (fixes None_service filename)
- Add path placeholder fallback param injection
- Harden requestBody & response schema handling across 3.0/3.1
@MarcoMuellner
Copy link
Owner

This is great! Thank you! I'll review this asap and give you feedback

Copy link
Owner

@MarcoMuellner MarcoMuellner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I generally like the changes - they are also much smaller then i would have assumed. So great work :) I do have some comments - maybe lets resolve those first, before i can approve it?

version = detect_openapi_version(data)

if version == "3.0":
openapi_obj = parse_openapi_30(data) # type: ignore[assignment]
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure why we would ignore the type here?


# Use version-specific generator
if version == "3.0":
result = generate_code_30(
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For both function i would prefer to replace . with an underscore, i.e. generate_code_3_0

if isinstance(reference_obj, Reference30):
return MediaType30(schema=reference_obj)
elif isinstance(reference_obj, Reference31):
return MediaType31(schema=reference_obj)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar for these types.

I am also not a 100% sure that this type of abstraction is ... good? It feels a bit icky to do it this way. Rather, i'd have a new type MediaType that within itself does the abstraction for it if you understand what i mean.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This goes for all other objects as well.

{%- endif %}
{% else %}
return response.json()
return body
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does feel a bit dangerous, as it breaks the current way the template works - and may cause isses for users. Is this strictly necessary for this change?

responses = "^0.25.7"
types-PyYAML = "^6.0.12.20240808"
types-requests = "^2.32.0.20241016"
types-urllib3 = "^1.26.25.14"
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please fix this - this doesn't work. Also not sure why this is needed for this change?

@MarcoMuellner MarcoMuellner merged commit c4e9faf into MarcoMuellner:main Sep 8, 2025
0 of 6 checks passed
@MarcoMuellner
Copy link
Owner

I took the liberty of improving on your work here - thank you doug! Keep them coming :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

OpenAPI 3.1 support

2 participants