polyfactory icon indicating copy to clipboard operation
polyfactory copied to clipboard

feat: add PEP 695 type alias support and improve type handling

Open Rub1kCube opened this issue 6 months ago • 1 comments

Summary

This PR adds full support for type aliases from PEP 695 (Python 3.12+) and improves overall type handling in polyfactory.

Key Changes

1. TypeCompatibilityAdapter Class

Added a new TypeCompatibilityAdapter class that serves as a compatibility layer for handling different type representations across Python versions. This adapter:

  • Problem it solves: PEP 695 introduces TypeAliasType, which requires special handling to extract the underlying type value. Polyfactory couldn't process this new type during data generation, which led to errors:
polyfactory.exceptions.ParameterException: Unsupported type: ExampleTypeAliasType on field 'example_field' from class FooFactory.
Either use 'add_provider', extend the providers map, or add a factory function for the field on the model.

The adapter also correctly handles nested scenarios such as list[ExampleTypeAliasType], resolves generic TypeAliasType, and cases where other TypeAliasType instances are used as generic type parameters.

Additionally, I've refactored type checking logic by introducing two utility methods:

  • is_generic_alias(): Checks if a type is a generic alias
  • is_type_var(): Checks if a type is a TypeVar

All instances of isinstance(value, TypeVar) have been replaced with is_type_var(value) for consistency. Comprehensive tests have been added to ensure the adapter works correctly with various type scenarios.

2. PydanticFieldMeta.from_field_info Refactoring

The from_field_info method has been decomposed into smaller, more focused methods to improve code readability and reduce cyclomatic complexity. This refactoring makes the code easier to understand and maintain without changing its functionality.

3. Rationale for the Chosen Approach

The type normalization in PydanticFieldMeta.from_field_info is implemented as:

field_info = FieldInfo.merge_field_infos(
    field_info, 
    FieldInfo.from_annotation(TypeCompatibilityAdapter(field_info.annotation).normalize())
)

This approach provides several benefits:

  • Clean implementation: Using normalization without conditional checks like is_type_alias improves code readability and eliminates the need for redundant tests that verify conditional behavior for each type scenario
  • Metadata preservation: Using merge_field_infos ensures that metadata like example values aren't lost during the annotation transformation

Testing

  • Added extensive test coverage for PEP 695 type aliases including:
    • Basic type aliases
    • Generic type aliases with single and multiple type parameters
    • Nested generic structures
    • Annotated types with constraints
    • Union types and optional types
    • Complex nested combinations
  • Added tests for the TypeCompatibilityAdapter class

Fixes #707

Rub1kCube avatar Jun 05 '25 08:06 Rub1kCube

Conflict has been fixed 👍

Rub1kCube avatar Jun 19 '25 10:06 Rub1kCube

Apologies - realised created another conflict for here when merging other things. Can this be updated again please?

adhtruong avatar Jun 21 '25 12:06 adhtruong

Apologies - realised created another conflict for here when merging other things. Can this be updated again please?

Conflict has been fixed

Rub1kCube avatar Jun 21 '25 12:06 Rub1kCube

Documentation preview will be available shortly at https://litestar-org.github.io/polyfactory-docs-preview/711

github-actions[bot] avatar Jun 21 '25 12:06 github-actions[bot]

https://github.com/all-contributors add @Rub1kCube for code

Thanks for the work on this!

adhtruong avatar Jun 21 '25 12:06 adhtruong