Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(python): handle non union self referencing schemas #4602

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions generators/python/sdk/versions.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
# For unreleased changes, use unreleased.yml
- version: 4.0.0-rc3
irVersion: 53
changelogEntry:
- type: fix
summary: |
Pydantic models now call update forward refs on non-uion circular references. This
dsinghvi marked this conversation as resolved.
Show resolved Hide resolved
prevents runtime errors in certain cases where types self reference itself through
a union.

- version: 4.0.0-rc2
irVersion: 53
changelogEntry:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ def get_class_reference_for_type_id(
def does_circularly_reference_itself(self, type_id: ir_types.TypeId) -> bool:
...

@abstractmethod
def get_non_union_circular_references(self) -> Set[ir_types.TypeId]:
...

@abstractmethod
def do_types_reference_each_other(self, a: ir_types.TypeId, b: ir_types.TypeId) -> bool:
...
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,15 @@ def __init__(
self._allow_leveraging_defaults = allow_leveraging_defaults
self._reserved_names: Set[str] = reserved_names or set()

self._non_union_self_referencing_type_ids = set()
for id, type in self.ir.types.items():
if (
id in type.referenced_types
and type.shape.get_as_union().type != "union"
and type.shape.get_as_union().type != "undiscriminatedUnion"
):
self._non_union_self_referencing_type_ids.add(id)

def get_module_path_in_project(self, module_path: AST.ModulePath) -> AST.ModulePath:
return self._project_module_path + module_path

Expand Down Expand Up @@ -135,6 +144,9 @@ def get_class_reference_for_type_id(
def does_circularly_reference_itself(self, type_id: ir_types.TypeId) -> bool:
return self.does_type_reference_other_type(type_id, type_id)

def get_non_union_circular_references(self) -> Set[ir_types.TypeId]:
return self._non_union_self_referencing_type_ids

def do_types_reference_each_other(self, a: ir_types.TypeId, b: ir_types.TypeId) -> bool:
return self.does_type_reference_other_type(a, b) and self.does_type_reference_other_type(b, a)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,20 @@ def _type_id_for_forward_ref(self) -> Optional[ir_types.TypeId]:

def _must_import_after_current_declaration(self, type_name: ir_types.DeclaredTypeName) -> bool:
type_id_to_reference = self._type_id_for_forward_ref()
is_circular_reference = False
should_import_after = False
if type_id_to_reference is not None:
is_circular_reference = self._context.does_type_reference_other_type(
should_import_after = self._context.does_type_reference_other_type(
type_id=type_name.type_id, other_type_id=type_id_to_reference
)

if is_circular_reference:
is_referencing_circular_reference = type_name.type_id in self._context.get_non_union_circular_references()
if is_referencing_circular_reference:
should_import_after = is_referencing_circular_reference

if should_import_after:
self._model_contains_forward_refs = True
return is_circular_reference

return should_import_after

def add_method(
self,
Expand Down

This file was deleted.

Loading