Skip to content

Support enum-field-as-literal in GraphQL parser#2677

Merged
koxudaxi merged 7 commits intokoxudaxi:mainfrom
siminn-arnorgj:support-literals-in-gql
Dec 18, 2025
Merged

Support enum-field-as-literal in GraphQL parser#2677
koxudaxi merged 7 commits intokoxudaxi:mainfrom
siminn-arnorgj:support-literals-in-gql

Conversation

@siminn-arnorgj
Copy link
Copy Markdown
Contributor

@siminn-arnorgj siminn-arnorgj commented Dec 17, 2025

Summary

  • Adds GraphQL support for the --enum-field-as-literal CLI option.
  • Adds tests for --enum-field-as-literal {all,one} and for --output-model-type typing.TypedDict (which generates enums as literals).

Notes

  • Enum member/value descriptions are not preserved when generating Literal[...] enums.

Fixes: #2497

Summary by CodeRabbit

Release Notes

  • New Features

    • Added support for generating GraphQL enums as Literal types with configurable options (all or one).
    • Enhanced enum handling when using TypedDict output model type.
  • Tests

    • Added comprehensive test coverage for new enum generation modes and TypedDict integration.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Dec 17, 2025

Walkthrough

The 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

Cohort / File(s) Summary
Core Parser Logic
src/datamodel_code_generator/parser/graphql.py
Added should_parse_enum_as_literal() helper method to determine enum output format; refactored parse_enum() to conditionally delegate to parse_enum_as_literal() or parse_enum_as_enum_class(); implemented both parsing strategies for Literal-based and Enum-class-based enum generation.
Expected Test Outputs
tests/data/expected/main/graphql/enum_literals_all.py, enum_literals_one.py, enums_typed_dict.py
Generated modules demonstrating expected output: enum_literals_all.py uses Pydantic BaseModel with __root__ Literal fields; enum_literals_one.py mixes traditional Enums with Pydantic Literal models; enums_typed_dict.py uses pure TypeAlias with Literal types for TypedDict output mode.
Test Cases
tests/main/graphql/test_main_graphql.py
Added three new test functions: test_main_graphql_enums_as_literals_all() for --enum-field-as-literal all, test_main_graphql_enums_as_literals_one() for --enum-field-as-literal one, and test_main_graphql_enums_to_typed_dict() for TypedDict output mode with enum handling.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

  • should_parse_enum_as_literal() decision logic: Verify correct conditions for determining when to emit Literals vs Enum classes
  • parse_enum_as_literal() and parse_enum_as_enum_class() implementations: Ensure both branches correctly generate their respective output structures
  • Generated output correctness: Validate that expected test files accurately represent the intended output for all three enum modes (all, one, TypedDict)

Possibly related PRs

Suggested reviewers

  • koxudaxi

Poem

🐰 Enums now bloom in Literal light,
Where GraphQL fields dance oh so bright—
No more rigid Enum class,
Literals shimmer, sleek and fast!
Types aligned, the parser's delight!

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: adding support for the enum-field-as-literal feature to the GraphQL parser.
Linked Issues check ✅ Passed The PR successfully addresses issue #2497 by implementing enum-field-as-literal support for GraphQL, generating Literal types instead of Enum classes.
Out of Scope Changes check ✅ Passed All changes focus on GraphQL enum parsing and literal support with corresponding tests. No unrelated or out-of-scope modifications detected.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
✨ Finishing touches
  • 📝 Generate docstrings
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

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_enums at 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

📥 Commits

Reviewing files that changed from the base of the PR and between 599ae84 and 9d61fac.

📒 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 with Literal['FIELD']

This aligns with the --enum-field-as-literal one behavior.

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_literal configuration (All or One with single value). This aligns with the jsonschema parser implementation.


413-417: LGTM! Delegation logic is clean and correct.

The parse_enum method 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
Copy link
Copy Markdown

codecov Bot commented Dec 17, 2025

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 99.51%. Comparing base (599ae84) to head (9d61fac).
⚠️ Report is 2 commits behind head on main.

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           
Flag Coverage Δ
unittests 99.51% <100.00%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@codspeed-hq
Copy link
Copy Markdown

codspeed-hq Bot commented Dec 17, 2025

CodSpeed Performance Report

Merging #2677 will not alter performance

Comparing siminn-arnorgj:support-literals-in-gql (9d61fac) with main (599ae84)

Summary

✅ 50 untouched
⏩ 3 skipped1

Footnotes

  1. 3 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase, click here and archive them to remove them from the performance reports.

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.

--enum-field-as-literal all doesn't work with GraphQL input files

2 participants