From 36cb98a289988df927d25082ee31c6ac6384506f Mon Sep 17 00:00:00 2001 From: Christodoulos Tsoulloftas Date: Sat, 30 Mar 2024 19:34:56 +0200 Subject: [PATCH] feat: Generate ForwardRef() instead of Type[] --- tests/formats/dataclass/test_filters.py | 30 ++++++++----------------- xsdata/formats/dataclass/filters.py | 15 +++++++------ 2 files changed, 17 insertions(+), 28 deletions(-) diff --git a/tests/formats/dataclass/test_filters.py b/tests/formats/dataclass/test_filters.py index 1c439a73f..ac8e613b2 100644 --- a/tests/formats/dataclass/test_filters.py +++ b/tests/formats/dataclass/test_filters.py @@ -770,40 +770,32 @@ def test_choice_type(self): actual = self.filters.choice_type(choice, ["a", "b"]) self.assertEqual("Type[Foobar]", actual) - self.filters.subscriptable_types = True - actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual("type[Foobar]", actual) - def test_choice_type_with_forward_reference(self): choice = AttrFactory.create( types=[AttrTypeFactory.create("foobar", forward=True)] ) actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual('Type["A.B.Foobar"]', actual) + self.assertEqual('ForwardRef("A.B.Foobar")', actual) def test_choice_type_with_circular_reference(self): choice = AttrFactory.create( types=[AttrTypeFactory.create("foobar", circular=True)] ) actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual('Type["Foobar"]', actual) + self.assertEqual('ForwardRef("Foobar")', actual) self.filters.postponed_annotations = True actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual('Type["Foobar"]', actual) + self.assertEqual('ForwardRef("Foobar")', actual) def test_choice_type_with_multiple_types(self): choice = AttrFactory.create(types=[type_str, type_bool]) actual = self.filters.choice_type(choice, ["a", "b"]) self.assertEqual("Type[Union[str, bool]]", actual) - self.filters.subscriptable_types = True - actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual("type[Union[str, bool]]", actual) - self.filters.union_type = True actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual("type[str | bool]", actual) + self.assertEqual("Type[str | bool]", actual) def test_choice_type_with_list_types_are_ignored(self): choice = AttrFactory.create(types=[type_str, type_bool]) @@ -824,7 +816,7 @@ def test_choice_type_with_restrictions_tokens_true(self): self.filters.union_type = True self.filters.subscriptable_types = True actual = self.filters.choice_type(choice, ["a", "b"]) - self.assertEqual("type[tuple[str | bool, ...]]", actual) + self.assertEqual("Type[tuple[str | bool, ...]]", actual) def test_default_imports_with_decimal(self): expected = "from decimal import Decimal" @@ -900,8 +892,8 @@ def test_default_imports_with_typing(self): expected = "from typing import Union" self.assertIn(expected, self.filters.default_imports(output)) - output = " Type[" - expected = "from typing import Type" + output = ": ForwardRef(" + expected = "from typing import ForwardRef" self.assertIn(expected, self.filters.default_imports(output)) output = ": Any = " @@ -946,8 +938,7 @@ def test_format_metadata(self): "level_two": {"a": 1}, "list": [ {"type": "Type[object]"}, - {"type": 'type["something"]'}, - {"type": "Type[object] mpla"}, + {"type": 'ForwardRef("something")'}, ], "default": "1", "default_factory": "list", @@ -969,10 +960,7 @@ def test_format_metadata(self): ' "type": object,\n' " },\n" " {\n" - ' "type": type["something"],\n' - " },\n" - " {\n" - ' "type": "Type[object] mpla",\n' + ' "type": ForwardRef("something"),\n' " },\n" " ],\n" ' "default": 1,\n' diff --git a/xsdata/formats/dataclass/filters.py b/xsdata/formats/dataclass/filters.py index f0198e201..dcd869125 100644 --- a/xsdata/formats/dataclass/filters.py +++ b/xsdata/formats/dataclass/filters.py @@ -557,10 +557,11 @@ def format_string(self, data: str, indent: int, key: str = "", pad: int = 0) -> length and the additional pad is more than the max line length, wrap the text into multiple lines, avoiding breaking long words """ - if (data.startswith("Type[") or data.startswith("type[")) and data.endswith( - "]" - ): - return data if data[5] == '"' else data[5:-1] + if data.startswith("ForwardRef("): + return data + + if data.startswith("Type["): + return data[5:-1] if data.startswith("Literal[") and data.endswith("]"): return data[8:-1] @@ -822,8 +823,8 @@ def choice_type(self, choice: Attr, parents: List[str]) -> str: iterable_fmt = self._get_iterable_format() result = iterable_fmt.format(result) - if self.subscriptable_types: - return f"type[{result}]" + if result.startswith('"'): + return f"ForwardRef({result})" return f"Type[{result}]" @@ -915,8 +916,8 @@ def build_import_patterns(cls) -> Dict[str, Dict]: "List": [": List["], "Optional": ["Optional["], "Tuple": ["Tuple["], - "Type": ["Type["], "Union": ["Union["], + "ForwardRef": [": ForwardRef("], "Any": type_patterns("Any"), }, "xml.etree.ElementTree": {"QName": type_patterns("QName")},