Support enum-field-as-literal in GraphQL parser#2677
Conversation
WalkthroughThe PR adds support for parsing GraphQL enums as Literal types instead of Enum classes. It introduces a conditional branching mechanism in the GraphQLParser to generate either Literal-based or Enum-class-based code based on configuration, with corresponding test cases validating the new behavior. Changes
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes
Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches✅ Passed checks (5 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 0
🧹 Nitpick comments (2)
tests/main/graphql/test_main_graphql.py (2)
168-177: Consider adding black version compatibility check.Other enum-related tests in this file (e.g.,
test_main_graphql_enumsat line 141) include@pytest.mark.skipif(black.__version__.split(".")[0] == "19", ...)to handle black compatibility. For consistency, consider adding the same decorator to these new enum tests.Apply this pattern if black 19 compatibility is a concern:
+@pytest.mark.skipif( + black.__version__.split(".")[0] == "19", + reason="Installed black doesn't support the old style", +) def test_main_graphql_enums_as_literals_all(output_file: Path) -> None:
180-189: Consider adding black version compatibility check.For consistency with other enum tests (e.g., line 141), consider adding the black version 19 skipif decorator.
📜 Review details
Configuration used: defaults
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (5)
src/datamodel_code_generator/parser/graphql.py(1 hunks)tests/data/expected/main/graphql/enum_literals_all.py(1 hunks)tests/data/expected/main/graphql/enum_literals_one.py(1 hunks)tests/data/expected/main/graphql/enums_typed_dict.py(1 hunks)tests/main/graphql/test_main_graphql.py(1 hunks)
🧰 Additional context used
🧬 Code graph analysis (5)
tests/data/expected/main/graphql/enum_literals_one.py (4)
src/datamodel_code_generator/model/enum.py (1)
Enum(39-120)src/datamodel_code_generator/model/type_alias.py (1)
TypeAlias(37-42)tests/data/expected/parser/openapi/openapi_parser_parse_enum_models/output.py (1)
Boolean(22-23)tests/data/expected/main/graphql/enum_literals_all.py (3)
Color(24-25)EmployeeShiftStatus(28-33)EnumWithOneField(36-37)
tests/main/graphql/test_main_graphql.py (1)
tests/main/conftest.py (2)
output_file(94-96)run_main_and_assert(196-352)
tests/data/expected/main/graphql/enum_literals_all.py (1)
src/datamodel_code_generator/model/type_alias.py (1)
TypeAlias(37-42)
src/datamodel_code_generator/parser/graphql.py (4)
src/datamodel_code_generator/parser/jsonschema.py (3)
should_parse_enum_as_literal(767-771)parse_enum(2507-2689)parse_enum_as_literal(2492-2494)src/datamodel_code_generator/parser/__init__.py (1)
LiteralType(17-21)src/datamodel_code_generator/parser/base.py (1)
data_type(972-974)src/datamodel_code_generator/reference.py (1)
reference(77-79)
tests/data/expected/main/graphql/enums_typed_dict.py (3)
src/datamodel_code_generator/model/type_alias.py (1)
TypeAlias(37-42)tests/data/expected/main/graphql/enum_literals_all.py (3)
Color(24-25)EmployeeShiftStatus(28-33)EnumWithOneField(36-37)tests/data/expected/main/graphql/enum_literals_one.py (3)
Color(25-28)EmployeeShiftStatus(31-37)EnumWithOneField(40-41)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (11)
- GitHub Check: 3.10 on macOS
- GitHub Check: 3.9 on Windows
- GitHub Check: 3.13 on Windows
- GitHub Check: 3.10 on Windows
- GitHub Check: 3.11 on Windows
- GitHub Check: 3.14 on Windows
- GitHub Check: 3.12 on Windows
- GitHub Check: 3.9 on macOS
- GitHub Check: 3.13 on macOS
- GitHub Check: benchmarks
- GitHub Check: Analyze (python)
🔇 Additional comments (8)
tests/main/graphql/test_main_graphql.py (1)
192-201: Test implementation looks good!The test correctly validates TypedDict output mode, which should generate enums as Literal type aliases rather than Enum classes or BaseModel wrappers.
tests/data/expected/main/graphql/enum_literals_one.py (1)
1-41: LGTM! Expected output correctly implements "one" mode.The generated file correctly shows that:
- Multi-value enums (
Color,EmployeeShiftStatus) remain as Enum classes- Single-value enum (
EnumWithOneField) becomes a BaseModel withLiteral['FIELD']This aligns with the
--enum-field-as-literal onebehavior.tests/data/expected/main/graphql/enums_typed_dict.py (1)
1-32: LGTM! TypedDict mode output is correct.The generated file correctly shows all GraphQL enums as
TypeAlias = Literal[...]declarations, which is the expected behavior for--output-model-type typing.TypedDict. Enum descriptions are preserved as module-level docstrings.tests/data/expected/main/graphql/enum_literals_all.py (1)
1-37: LGTM! Expected output correctly implements "all" mode.The generated file correctly shows all GraphQL enums as Pydantic BaseModel classes with
__root__: Literal[...]fields, which is the expected behavior for--enum-field-as-literal all. Enum descriptions are preserved as class docstrings.src/datamodel_code_generator/parser/graphql.py (4)
407-411: LGTM! Enum-as-literal decision logic is correct.The method correctly determines whether to parse an enum as a Literal type based on the
enum_field_as_literalconfiguration (AllorOnewith single value). This aligns with the jsonschema parser implementation.
413-417: LGTM! Delegation logic is clean and correct.The
parse_enummethod now correctly routes to either literal or enum-class parsing based on the configuration. The implementation is straightforward and maintainable.
419-437: LGTM! Literal parsing implementation is correct.The method correctly creates a root model with a Literal data type containing all enum values. Note that individual enum value descriptions are not preserved in Literal types (as documented in the PR description), which is expected since Python's Literal type doesn't support per-value descriptions.
439-484: LGTM! Enum class parsing logic is sound.This method contains the original enum parsing logic (now extracted for clarity), which correctly generates Enum classes with proper field handling, specialized enum support for Python 3.11+, and preservation of individual value descriptions.
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #2677 +/- ##
=======================================
Coverage 99.51% 99.51%
=======================================
Files 79 79
Lines 11001 11017 +16
Branches 1318 1319 +1
=======================================
+ Hits 10948 10964 +16
Misses 32 32
Partials 21 21
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
CodSpeed Performance ReportMerging #2677 will not alter performanceComparing Summary
Footnotes
|
Summary
--enum-field-as-literalCLI option.--enum-field-as-literal {all,one}and for--output-model-type typing.TypedDict(which generates enums as literals).Notes
Literal[...]enums.Fixes: #2497
Summary by CodeRabbit
Release Notes
New Features
allorone).Tests
✏️ Tip: You can customize this high-level summary in your review settings.