Skip to content

Conversation

@devin-ai-integration
Copy link
Contributor

@devin-ai-integration devin-ai-integration bot commented Nov 21, 2025

Description

Refs https://buildwithfern.slack.com/archives/C09NRQZ4A2X/p1763684501766159

Adds type-safe casting methods for discriminated union types in the Python SDK generator, matching the pattern used in the PHP generator. For each union variant, the generator now creates:

  • is_*() methods to check if the union is of a specific variant type
  • as_*() methods to cast to the specific type with runtime validation

Changes Made

  • Added _add_is_method() to generate boolean type-checking methods for each union variant
  • Added _add_as_method() to generate typed casting methods with runtime validation
  • Both methods support Pydantic v1/v2 compatibility using the existing add_statements_v1_v2_or_both pattern
  • Added version entry 4.39.0 in generators/python/sdk/versions.yml
  • Methods are generated in discriminated_union_with_utils_generator.py for all discriminated union types

Example Generated Code:

animal: Animal = Animal.factory.dog(Dog(name="Fido"))

if animal.is_dog():
    dog = animal.as_dog()  # Returns Dog type
    print(dog.name)

# Raises ValueError if wrong type
cat = animal.as_cat()  # ValueError: Expected cat; got dog

Testing

  • All CI checks passed (compile, lint, fastapi, python-sdk, pydantic seed tests)
  • Verified Pydantic v1/v2 compatibility through seed tests
  • Pre-commit hooks passed (ruff format, mypy)

Review Focus Areas

Critical Items:

  1. AST Node Rendering: The implementation uses writer.write_node() for AST.Expression objects. Verify this pattern is correct and doesn't cause syntax errors in edge cases.
  2. Pydantic v1/v2 Dual Paths: Check that both self.__root__ (v1) and self.root (v2) paths work correctly in the generated code.
  3. Object Reconstruction: The as_*() methods reconstruct typed objects using dict(exclude_unset=True, exclude={discriminant}). Verify this correctly handles all union variant shapes (same_properties_as_object, single_property, no_properties).
  4. No Properties Case: When a union variant has no properties, as_*() returns None. Confirm this is the expected behavior.

Implementation Notes:

  • The methods are added after the visit() method in the generation flow
  • Return types are computed based on the union variant shape
  • Error messages include the expected and actual discriminant values for debugging

Devin Session: https://app.devin.ai/sessions/57d48c907d15446caf2c77e9700bb45d
Requested by: [email protected] (@aditya-arolkar-swe)

@devin-ai-integration
Copy link
Contributor Author

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@devin-ai-integration devin-ai-integration bot changed the title feat(python): add is_* and as_* casting methods for discriminated union types feat(python): add is_* and as_* casting methods for discriminated unions Nov 21, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

1 participant