From 0b1d1601925d92fec184f02da3f8c5dea230da73 Mon Sep 17 00:00:00 2001 From: Christodoulos Tsoulloftas Date: Fri, 6 Dec 2024 08:09:21 +0200 Subject: [PATCH] Update pre-commit hooks --- .pre-commit-config.yaml | 10 +- pyproject.toml | 5 +- .../handlers/test_vacuum_inner_classes.py | 2 +- tests/codegen/mappers/test_definitions.py | 2 +- tests/codegen/mappers/test_dtd.py | 2 +- tests/codegen/mappers/test_schema.py | 2 +- tests/codegen/models/test_codegen.py | 3 +- tests/codegen/test_utils.py | 2 +- tests/codegen/test_writer.py | 4 +- tests/conftest.py | 3 +- tests/fixtures/artists/metadata.py | 8 +- tests/fixtures/books/books.py | 4 +- tests/fixtures/compound/models.py | 6 +- tests/fixtures/dtd/models/complete_example.py | 10 +- tests/fixtures/models.py | 2 - tests/fixtures/primer/order.py | 4 +- tests/fixtures/series/series.py | 6 +- tests/fixtures/stripe/models/balance.py | 8 +- tests/fixtures/wrapper/models.py | 10 +- .../formats/dataclass/models/test_builders.py | 7 +- .../dataclass/parsers/nodes/test_wrapper.py | 7 +- tests/formats/dataclass/parsers/test_dict.py | 13 +- tests/formats/dataclass/parsers/test_node.py | 4 +- .../dataclass/serializers/test_mixins.py | 8 +- tests/formats/dataclass/test_typing.py | 6 +- tests/formats/test_mixins.py | 4 +- tests/models/test_datatype.py | 3 +- tests/models/test_mixins.py | 2 +- tests/models/wsdl/test_definitions.py | 2 +- tests/models/xsd/test_restriction.py | 2 +- tests/models/xsd/test_schema.py | 2 +- tests/models/xsd/test_union.py | 2 +- tests/utils/test_collections.py | 2 +- tests/utils/test_namespaces.py | 5 +- xsdata/cli.py | 3 +- xsdata/codegen/container.py | 9 +- .../handlers/add_attribute_substitutions.py | 4 +- .../handlers/create_compound_fields.py | 17 +- .../codegen/handlers/create_wrapper_fields.py | 4 +- .../handlers/designate_class_packages.py | 11 +- .../handlers/detect_circular_references.py | 6 +- .../codegen/handlers/disambiguate_choices.py | 2 +- xsdata/codegen/handlers/filter_classes.py | 4 +- xsdata/codegen/handlers/merge_attributes.py | 4 +- .../handlers/process_attributes_types.py | 4 +- .../handlers/rename_duplicate_classes.py | 16 +- .../handlers/sanitize_enumeration_class.py | 4 +- .../codegen/handlers/unnest_inner_classes.py | 6 +- .../update_attributes_effective_choice.py | 7 +- .../codegen/handlers/vacuum_inner_classes.py | 2 +- .../handlers/validate_attributes_overrides.py | 10 +- .../codegen/handlers/validate_references.py | 4 +- xsdata/codegen/mappers/definitions.py | 23 +-- xsdata/codegen/mappers/dict.py | 6 +- xsdata/codegen/mappers/dtd.py | 7 +- xsdata/codegen/mappers/element.py | 10 +- xsdata/codegen/mappers/schema.py | 15 +- xsdata/codegen/mixins.py | 13 +- xsdata/codegen/models.py | 35 ++-- xsdata/codegen/parsers/definitions.py | 6 +- xsdata/codegen/parsers/dtd.py | 4 +- xsdata/codegen/parsers/schema.py | 22 +-- xsdata/codegen/resolver.py | 29 ++-- xsdata/codegen/stopwatch.py | 3 +- xsdata/codegen/transformer.py | 34 ++-- xsdata/codegen/utils.py | 21 +-- xsdata/codegen/validator.py | 10 +- xsdata/codegen/writer.py | 8 +- xsdata/formats/converter.py | 32 ++-- xsdata/formats/dataclass/client.py | 14 +- xsdata/formats/dataclass/compat.py | 21 +-- xsdata/formats/dataclass/context.py | 39 ++--- xsdata/formats/dataclass/generator.py | 16 +- xsdata/formats/dataclass/models/builders.py | 45 +++-- xsdata/formats/dataclass/models/elements.py | 31 ++-- xsdata/formats/dataclass/models/generics.py | 6 +- xsdata/formats/dataclass/parsers/bases.py | 53 +++--- xsdata/formats/dataclass/parsers/config.py | 6 +- xsdata/formats/dataclass/parsers/dict.py | 27 +-- .../dataclass/parsers/handlers/__init__.py | 6 +- .../dataclass/parsers/handlers/lxml.py | 9 +- .../dataclass/parsers/handlers/native.py | 13 +- xsdata/formats/dataclass/parsers/json.py | 12 +- xsdata/formats/dataclass/parsers/mixins.py | 50 +++--- .../dataclass/parsers/nodes/element.py | 53 +++--- .../dataclass/parsers/nodes/primitive.py | 8 +- .../formats/dataclass/parsers/nodes/skip.py | 6 +- .../dataclass/parsers/nodes/standard.py | 10 +- .../formats/dataclass/parsers/nodes/union.py | 16 +- .../dataclass/parsers/nodes/wildcard.py | 14 +- .../dataclass/parsers/nodes/wrapper.py | 6 +- xsdata/formats/dataclass/parsers/tree.py | 14 +- xsdata/formats/dataclass/parsers/utils.py | 21 +-- xsdata/formats/dataclass/parsers/xml.py | 22 +-- xsdata/formats/dataclass/serializers/code.py | 17 +- .../formats/dataclass/serializers/config.py | 4 +- xsdata/formats/dataclass/serializers/dict.py | 7 +- .../formats/dataclass/serializers/mixins.py | 44 +++-- xsdata/formats/dataclass/serializers/tree.py | 4 +- .../dataclass/serializers/writers/__init__.py | 4 +- .../dataclass/serializers/writers/lxml.py | 2 +- .../dataclass/serializers/writers/native.py | 4 +- xsdata/formats/dataclass/serializers/xml.py | 8 +- xsdata/formats/dataclass/transports.py | 10 +- xsdata/formats/dataclass/typing.py | 14 +- xsdata/formats/mixins.py | 11 +- xsdata/models/datatype.py | 6 +- xsdata/models/dtd.py | 10 +- xsdata/models/enums.py | 10 +- xsdata/models/mixins.py | 13 +- xsdata/models/wsdl.py | 35 ++-- xsdata/models/xsd.py | 160 +++++++++--------- xsdata/utils/click.py | 13 +- xsdata/utils/collections.py | 24 +-- xsdata/utils/constants.py | 7 +- xsdata/utils/dates.py | 3 +- xsdata/utils/downloader.py | 6 +- xsdata/utils/graphs.py | 14 +- xsdata/utils/namespaces.py | 14 +- xsdata/utils/testing.py | 41 ++--- 120 files changed, 758 insertions(+), 802 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 01cd0c282..daea7b66a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,12 +8,12 @@ repos: - id: end-of-file-fixer - id: debug-statements - repo: https://github.com/crate-ci/typos - rev: v1.27.0 + rev: v1.28.2 hooks: - id: typos exclude: ^tests/|.xsd|xsdata/models/datatype.py$ - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.7.2 + rev: v0.8.2 hooks: - id: ruff args: [ --fix, --show-fixes] @@ -31,11 +31,9 @@ repos: - types-docutils - types-toposort args: [ "--check-untyped-defs", "--ignore-missing-imports" ] - - repo: https://github.com/pre-commit/mirrors-prettier - rev: v4.0.0-alpha.8 + - repo: https://github.com/rbubley/mirrors-prettier + rev: v3.4.2 hooks: - id: prettier - additional_dependencies: - - prettier@3.2.5 types_or: [markdown] args: [--prose-wrap=always, --print-width=88] diff --git a/pyproject.toml b/pyproject.toml index 126f2dfb3..6d361be08 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -83,7 +83,7 @@ license-files = ["LICENSE"] version = {attr = "xsdata.__version__"} [tool.ruff] -target-version = "py38" +target-version = "py39" [tool.ruff.lint] select = [ @@ -114,8 +114,6 @@ select = [ ] ignore = [ - "ANN101", - "ANN102", "ANN201", "ANN202", "ANN204", @@ -133,6 +131,7 @@ ignore = [ [tool.ruff.lint.per-file-ignores] "**/{tests}/*" = ["ANN001", "ANN002", "ANN003", "E501", "B018", "D"] +"tests/formats/dataclass/cases/**" = ["UP"] "**/utils/testing.py" = ["D"] "docs/*" = ["D"] diff --git a/tests/codegen/handlers/test_vacuum_inner_classes.py b/tests/codegen/handlers/test_vacuum_inner_classes.py index f11216bca..d922b7e65 100644 --- a/tests/codegen/handlers/test_vacuum_inner_classes.py +++ b/tests/codegen/handlers/test_vacuum_inner_classes.py @@ -1,4 +1,4 @@ -from typing import Generator +from collections.abc import Generator from xsdata.codegen.handlers import VacuumInnerClasses from xsdata.models.enums import DataType diff --git a/tests/codegen/mappers/test_definitions.py b/tests/codegen/mappers/test_definitions.py index 12de60b5b..07c91cfd7 100644 --- a/tests/codegen/mappers/test_definitions.py +++ b/tests/codegen/mappers/test_definitions.py @@ -1,4 +1,4 @@ -from typing import Generator +from collections.abc import Generator from unittest import mock from xsdata.codegen.mappers import DefinitionsMapper diff --git a/tests/codegen/mappers/test_dtd.py b/tests/codegen/mappers/test_dtd.py index e437d9287..c71c1a232 100644 --- a/tests/codegen/mappers/test_dtd.py +++ b/tests/codegen/mappers/test_dtd.py @@ -1,5 +1,5 @@ import sys -from typing import Iterator +from collections.abc import Iterator from unittest import mock from xsdata.codegen.mappers import DtdMapper diff --git a/tests/codegen/mappers/test_schema.py b/tests/codegen/mappers/test_schema.py index fc514993b..a505f84a9 100644 --- a/tests/codegen/mappers/test_schema.py +++ b/tests/codegen/mappers/test_schema.py @@ -1,5 +1,5 @@ +from collections.abc import Iterator from types import GeneratorType -from typing import Iterator from unittest import mock from xsdata.codegen.mappers import SchemaMapper diff --git a/tests/codegen/models/test_codegen.py b/tests/codegen/models/test_codegen.py index 9fcd146c9..66f8d8ce1 100644 --- a/tests/codegen/models/test_codegen.py +++ b/tests/codegen/models/test_codegen.py @@ -1,13 +1,12 @@ import unittest from dataclasses import dataclass -from typing import List from xsdata.codegen.models import CodegenModel @dataclass class Foo(CodegenModel): - bar: List["Bar"] + bar: list["Bar"] @dataclass class Bar(CodegenModel): diff --git a/tests/codegen/test_utils.py b/tests/codegen/test_utils.py index 864f34408..540450d44 100644 --- a/tests/codegen/test_utils.py +++ b/tests/codegen/test_utils.py @@ -1,5 +1,5 @@ import sys -from typing import Generator +from collections.abc import Generator from unittest import mock from xsdata.codegen.exceptions import CodegenError diff --git a/tests/codegen/test_writer.py b/tests/codegen/test_writer.py index 82ba694d3..5398dc2a1 100644 --- a/tests/codegen/test_writer.py +++ b/tests/codegen/test_writer.py @@ -1,6 +1,6 @@ +from collections.abc import Iterator from pathlib import Path from tempfile import TemporaryDirectory -from typing import Iterator, List from unittest import mock from xsdata.codegen.exceptions import CodegenError @@ -13,7 +13,7 @@ class NoneGenerator(AbstractGenerator): - def render(self, classes: List[Class]) -> Iterator[GeneratorResult]: + def render(self, classes: list[Class]) -> Iterator[GeneratorResult]: pass diff --git a/tests/conftest.py b/tests/conftest.py index 00fc3679e..88ae09339 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,5 +1,4 @@ from pathlib import Path -from typing import Type from lxml import etree @@ -13,7 +12,7 @@ from xsdata.formats.dataclass.serializers.config import SerializerConfig -def validate_bindings(schema: Path, clazz: Type): +def validate_bindings(schema: Path, clazz: type): __tracebackhide__ = True sample = schema.parent.joinpath("sample.xml") diff --git a/tests/fixtures/artists/metadata.py b/tests/fixtures/artists/metadata.py index 87d01e423..61f0541e4 100644 --- a/tests/fixtures/artists/metadata.py +++ b/tests/fixtures/artists/metadata.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional, Union +from typing import Optional, Union from xsdata.models.datatype import XmlDate, XmlPeriod @@ -111,7 +111,7 @@ class Meta: name = "ipi-list" namespace = "http://musicbrainz.org/ns/mmd-2.0#" - ipi: List[str] = field( + ipi: list[str] = field( default_factory=list, metadata={ "type": "Element", @@ -126,7 +126,7 @@ class Meta: name = "isni-list" namespace = "http://musicbrainz.org/ns/mmd-2.0#" - isni: List[str] = field( + isni: list[str] = field( default_factory=list, metadata={ "type": "Element", @@ -207,7 +207,7 @@ class Meta: "required": True, }, ) - alias: List[Alias] = field( + alias: list[Alias] = field( default_factory=list, metadata={ "type": "Element", diff --git a/tests/fixtures/books/books.py b/tests/fixtures/books/books.py index e4d55ac4c..3a0bc917f 100644 --- a/tests/fixtures/books/books.py +++ b/tests/fixtures/books/books.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional +from typing import Optional from xsdata.models.datatype import XmlDate @@ -87,7 +87,7 @@ class BookForm: @dataclass class BooksForm: - book: List[BookForm] = field( + book: list[BookForm] = field( default_factory=list, metadata={ "type": "Element", diff --git a/tests/fixtures/compound/models.py b/tests/fixtures/compound/models.py index abf5fc960..f555276a2 100644 --- a/tests/fixtures/compound/models.py +++ b/tests/fixtures/compound/models.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Union +from typing import Union @dataclass @@ -35,7 +35,7 @@ class Root: class Meta: name = "root" - alpha_or_bravo_or_charlie: List[Union[Alpha, Bravo, List[str]]] = field( + alpha_or_bravo_or_charlie: list[Union[Alpha, Bravo, list[str]]] = field( default_factory=list, metadata={ "type": "Elements", @@ -50,7 +50,7 @@ class Meta: }, { "name": "charlie", - "type": List[str], + "type": list[str], "namespace": "", "default_factory": list, "tokens": True, diff --git a/tests/fixtures/dtd/models/complete_example.py b/tests/fixtures/dtd/models/complete_example.py index edeeba953..e2c97b30c 100644 --- a/tests/fixtures/dtd/models/complete_example.py +++ b/tests/fixtures/dtd/models/complete_example.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field from enum import Enum -from typing import List, Optional +from typing import Optional @dataclass @@ -60,7 +60,7 @@ class Title: @dataclass class Tags: - tag: List[Tag] = field( + tag: list[Tag] = field( default_factory=list, metadata={ "name": "Tag", @@ -100,14 +100,14 @@ class Post: "required": True, }, ) - origin: List[Origin] = field( + origin: list[Origin] = field( default_factory=list, metadata={ "name": "Origin", "type": "Element", }, ) - source: List[Source] = field( + source: list[Source] = field( default_factory=list, metadata={ "name": "Source", @@ -142,7 +142,7 @@ class Post: @dataclass class Blog: - post: List[Post] = field( + post: list[Post] = field( default_factory=list, metadata={ "name": "Post", diff --git a/tests/fixtures/models.py b/tests/fixtures/models.py index b841ca17f..581a3d792 100644 --- a/tests/fixtures/models.py +++ b/tests/fixtures/models.py @@ -8,8 +8,6 @@ from typing import Union from xml.etree.ElementTree import QName -from xsdata.utils.constants import return_true - __NAMESPACE__ = "xsdata" diff --git a/tests/fixtures/primer/order.py b/tests/fixtures/primer/order.py index 1495572ac..e7f338db3 100644 --- a/tests/fixtures/primer/order.py +++ b/tests/fixtures/primer/order.py @@ -1,6 +1,6 @@ from dataclasses import dataclass, field from decimal import Decimal -from typing import List, Optional +from typing import Optional from xsdata.models.datatype import XmlDate @@ -74,7 +74,7 @@ class Meta: @dataclass class Items: - item: List["Items.Item"] = field( + item: list["Items.Item"] = field( default_factory=list, metadata={ "type": "Element", diff --git a/tests/fixtures/series/series.py b/tests/fixtures/series/series.py index cff7c716a..674b49be5 100644 --- a/tests/fixtures/series/series.py +++ b/tests/fixtures/series/series.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional +from typing import Optional from xsdata.models.datatype import XmlDate @@ -119,7 +119,7 @@ class Meta: "required": True, }, ) - days: List[str] = field( + days: list[str] = field( default_factory=list, metadata={ "type": "Element", @@ -231,7 +231,7 @@ class Meta: "required": True, }, ) - genres: List[str] = field( + genres: list[str] = field( default_factory=list, metadata={ "type": "Element", diff --git a/tests/fixtures/stripe/models/balance.py b/tests/fixtures/stripe/models/balance.py index 47719fb8f..60b6dc0ff 100644 --- a/tests/fixtures/stripe/models/balance.py +++ b/tests/fixtures/stripe/models/balance.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Optional, Tuple +from typing import Optional @dataclass(order=True, frozen=True) @@ -113,14 +113,14 @@ class Meta: "required": True, }, ) - available: Tuple[Available, ...] = field( + available: tuple[Available, ...] = field( default_factory=tuple, metadata={ "type": "Element", "min_occurs": 1, }, ) - connect_reserved: Tuple[ConnectReserved, ...] = field( + connect_reserved: tuple[ConnectReserved, ...] = field( default_factory=tuple, metadata={ "type": "Element", @@ -134,7 +134,7 @@ class Meta: "required": True, }, ) - pending: Tuple[Pending, ...] = field( + pending: tuple[Pending, ...] = field( default_factory=tuple, metadata={ "type": "Element", diff --git a/tests/fixtures/wrapper/models.py b/tests/fixtures/wrapper/models.py index 0ec44b800..abcaed627 100644 --- a/tests/fixtures/wrapper/models.py +++ b/tests/fixtures/wrapper/models.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import List, Optional +from typing import Optional __NAMESPACE__ = "xsdata" @@ -25,7 +25,7 @@ class Meta: name = "bravos" namespace = "xsdata" - bravo: List[int] = field( + bravo: list[int] = field( default_factory=list, metadata={ "type": "Element", @@ -60,7 +60,7 @@ class Meta: name = "charlies" namespace = "xsdata" - charlie: List[Charlie] = field( + charlie: list[Charlie] = field( default_factory=list, metadata={ "type": "Element", @@ -83,7 +83,7 @@ class Meta: "required": True, }, ) - bravo: List[int] = field( + bravo: list[int] = field( default_factory=list, metadata={ "wrapper": "bravos", @@ -91,7 +91,7 @@ class Meta: "min_occurs": 1, }, ) - charlie: List[Charlie] = field( + charlie: list[Charlie] = field( default_factory=list, metadata={ "wrapper": "charlies", diff --git a/tests/formats/dataclass/models/test_builders.py b/tests/formats/dataclass/models/test_builders.py index 5523f0188..f43442a89 100644 --- a/tests/formats/dataclass/models/test_builders.py +++ b/tests/formats/dataclass/models/test_builders.py @@ -1,7 +1,8 @@ import sys +from collections.abc import Iterator from dataclasses import dataclass, field, fields, make_dataclass from decimal import Decimal -from typing import Iterator, List, get_type_hints +from typing import get_type_hints from unittest import TestCase, mock from xml.etree.ElementTree import QName @@ -392,7 +393,7 @@ def test_build_validates_result(self): self.builder.build( BookForm, "foo", - List[int], + list[int], {"type": "Attributes"}, True, None, @@ -401,7 +402,7 @@ def test_build_validates_result(self): ) self.assertEqual( - "Error on BookForm::foo: Xml Attributes does not support typing `typing.List[int]`", + "Error on BookForm::foo: Xml Attributes does not support typing `list[int]`", str(cm.exception), ) diff --git a/tests/formats/dataclass/parsers/nodes/test_wrapper.py b/tests/formats/dataclass/parsers/nodes/test_wrapper.py index 536af3275..7a5c4e4a2 100644 --- a/tests/formats/dataclass/parsers/nodes/test_wrapper.py +++ b/tests/formats/dataclass/parsers/nodes/test_wrapper.py @@ -1,5 +1,4 @@ from dataclasses import dataclass, field -from typing import List from unittest import TestCase from xsdata.formats.dataclass.parsers import XmlParser @@ -12,7 +11,7 @@ def setUp(self) -> None: def test_namespace(self): @dataclass class NamespaceWrapper: - items: List[str] = field( + items: list[str] = field( metadata={ "wrapper": "Items", "type": "Element", @@ -32,7 +31,7 @@ class NamespaceWrapper: def test_primitive(self): @dataclass class PrimitiveWrapper: - primitive_list: List[str] = field( + primitive_list: list[str] = field( metadata={ "wrapper": "PrimitiveList", "type": "Element", @@ -55,7 +54,7 @@ class ElementObject: @dataclass class ElementWrapper: - elements: List[ElementObject] = field( + elements: list[ElementObject] = field( metadata={"wrapper": "Elements", "type": "Element", "name": "Object"} ) diff --git a/tests/formats/dataclass/parsers/test_dict.py b/tests/formats/dataclass/parsers/test_dict.py index e9b7c783e..67f602f28 100644 --- a/tests/formats/dataclass/parsers/test_dict.py +++ b/tests/formats/dataclass/parsers/test_dict.py @@ -1,7 +1,7 @@ import json from dataclasses import asdict, dataclass, field from decimal import Decimal -from typing import List, Optional, Union +from typing import Optional, Union from xml.etree.ElementTree import QName from tests import fixtures_dir @@ -69,14 +69,14 @@ def test_decode(self): def test_decode_empty_document(self): self.assertEqual(BookForm(), self.decoder.decode({}, BookForm)) - self.assertEqual([], self.decoder.decode([], List[BookForm])) + self.assertEqual([], self.decoder.decode([], list[BookForm])) def test_decode_list_of_objects(self): path = fixtures_dir.joinpath("books/books.json") data = json.loads(path.read_text()) book_list = data["book"] - books = self.decoder.decode(book_list, List[BookForm]) + books = self.decoder.decode(book_list, list[BookForm]) self.assertIsInstance(books, list) self.assertEqual(2, len(books)) self.assertIsInstance(books[0], BookForm) @@ -138,14 +138,13 @@ def test_verify_type(self): ), ({}, None, "Document is empty, can not detect type"), ([], BookForm, "Document is array, expected object"), - ({}, List[BookForm], "Document is object, expected array"), + ({}, list[BookForm], "Document is object, expected array"), ( {}, Optional[ChoiceType], f"Invalid clazz argument: {Optional[ChoiceType]}", ), - ([], List[int], f"Invalid clazz argument: {List[int]}"), - ([], List, f"Invalid clazz argument: {List}"), + ([], list[int], f"Invalid clazz argument: {list[int]}"), ] for source, clazz, exc_msg in invalid_cases: @@ -391,7 +390,7 @@ def test_bind_any_type_with_derived_dataclass(self): def test_bind_text_with_unions(self): @dataclass class Fixture: - x: List[Union[int, float, str, bool]] = field(metadata={"tokens": True}) + x: list[Union[int, float, str, bool]] = field(metadata={"tokens": True}) values = ["foo", 12.2, "12.2", 12, "12", True, "false"] diff --git a/tests/formats/dataclass/parsers/test_node.py b/tests/formats/dataclass/parsers/test_node.py index 4bfef17ab..cf787c74f 100644 --- a/tests/formats/dataclass/parsers/test_node.py +++ b/tests/formats/dataclass/parsers/test_node.py @@ -1,5 +1,5 @@ from dataclasses import make_dataclass -from typing import Any, Dict +from typing import Any from unittest import mock from unittest.case import TestCase @@ -25,7 +25,7 @@ def setUp(self): def test_parse(self): class TestHandler(XmlHandler): - def parse(self, source: Any, ns_map: Dict) -> Any: + def parse(self, source: Any, ns_map: dict) -> Any: return Books() self.parser.handler = TestHandler diff --git a/tests/formats/dataclass/serializers/test_mixins.py b/tests/formats/dataclass/serializers/test_mixins.py index e79cd1c19..ca5bc2af6 100644 --- a/tests/formats/dataclass/serializers/test_mixins.py +++ b/tests/formats/dataclass/serializers/test_mixins.py @@ -1,6 +1,6 @@ +from collections.abc import Generator from dataclasses import dataclass, field, make_dataclass from io import StringIO -from typing import Generator, List from unittest import TestCase from xml.etree.ElementTree import QName from xml.sax import ContentHandler @@ -215,7 +215,7 @@ def setUp(self) -> None: def test_with_primitive_wrapper(self): @dataclass class PrimitiveWrapper: - primitive_list: List[str] = field( + primitive_list: list[str] = field( metadata={ "wrapper": "PrimitiveList", "type": "Element", @@ -246,7 +246,7 @@ class ElementObject: @dataclass class ElementWrapper: - elements: List[ElementObject] = field( + elements: list[ElementObject] = field( metadata={"wrapper": "Elements", "type": "Element", "name": "Object"} ) @@ -275,7 +275,7 @@ class ElementWrapper: def test_with_wrapper_namespace(self): @dataclass class NamespaceWrapper: - items: List[str] = field( + items: list[str] = field( metadata={ "wrapper": "Items", "type": "Element", diff --git a/tests/formats/dataclass/test_typing.py b/tests/formats/dataclass/test_typing.py index ea0d8fac3..5832e9126 100644 --- a/tests/formats/dataclass/test_typing.py +++ b/tests/formats/dataclass/test_typing.py @@ -1,5 +1,3 @@ -from typing import Type - import pytest from tests.formats.dataclass.cases import ( @@ -20,11 +18,11 @@ def test_evaluate_with_typevar(): - result = evaluate(Type["str"], None) + result = evaluate(type["str"], None) assert result is str with pytest.raises(TypeError): - evaluate(Type, None) + evaluate(type["str", "int"], None) @pytest.mark.parametrize("case,expected", attribute.tokens) diff --git a/tests/formats/test_mixins.py b/tests/formats/test_mixins.py index 399c735f1..1fc884ac5 100644 --- a/tests/formats/test_mixins.py +++ b/tests/formats/test_mixins.py @@ -1,5 +1,5 @@ import datetime -from typing import Iterator, List +from collections.abc import Iterator from unittest import mock from xsdata import __version__ @@ -11,7 +11,7 @@ class NoneGenerator(AbstractGenerator): - def render(self, classes: List[Class]) -> Iterator[GeneratorResult]: + def render(self, classes: list[Class]) -> Iterator[GeneratorResult]: """Do nothing.""" diff --git a/tests/models/test_datatype.py b/tests/models/test_datatype.py index e10d24587..bd23a63e5 100644 --- a/tests/models/test_datatype.py +++ b/tests/models/test_datatype.py @@ -1,11 +1,10 @@ from datetime import date, datetime, time, timedelta, timezone -from typing import Dict from unittest import TestCase from xsdata.models.datatype import XmlDate, XmlDateTime, XmlDuration, XmlPeriod, XmlTime -def filter_none(mapping: Dict) -> Dict: +def filter_none(mapping: dict) -> dict: return {k: v for k, v in mapping.items() if v is not None} diff --git a/tests/models/test_mixins.py b/tests/models/test_mixins.py index bc72edd83..4b0cce638 100644 --- a/tests/models/test_mixins.py +++ b/tests/models/test_mixins.py @@ -1,4 +1,4 @@ -from typing import Generator, Iterator +from collections.abc import Generator, Iterator from unittest import TestCase from xsdata.codegen.exceptions import CodegenError diff --git a/tests/models/wsdl/test_definitions.py b/tests/models/wsdl/test_definitions.py index 6f9fc5233..b91273443 100644 --- a/tests/models/wsdl/test_definitions.py +++ b/tests/models/wsdl/test_definitions.py @@ -1,5 +1,5 @@ import copy -from typing import Generator +from collections.abc import Generator from unittest import TestCase from xsdata.codegen.exceptions import CodegenError diff --git a/tests/models/xsd/test_restriction.py b/tests/models/xsd/test_restriction.py index 8e8aeb23a..d6773f783 100644 --- a/tests/models/xsd/test_restriction.py +++ b/tests/models/xsd/test_restriction.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from unittest import TestCase from xsdata.models.xsd import ( diff --git a/tests/models/xsd/test_schema.py b/tests/models/xsd/test_schema.py index f574cd26e..2fcb2279f 100644 --- a/tests/models/xsd/test_schema.py +++ b/tests/models/xsd/test_schema.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from unittest import TestCase from xsdata.models.enums import Namespace diff --git a/tests/models/xsd/test_union.py b/tests/models/xsd/test_union.py index fd036a590..ca5fb08e9 100644 --- a/tests/models/xsd/test_union.py +++ b/tests/models/xsd/test_union.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from unittest import TestCase from xsdata.models.xsd import ( diff --git a/tests/utils/test_collections.py b/tests/utils/test_collections.py index 2d460a7db..b2e385dd7 100644 --- a/tests/utils/test_collections.py +++ b/tests/utils/test_collections.py @@ -1,5 +1,5 @@ from collections import namedtuple -from typing import Iterator +from collections.abc import Iterator from unittest import TestCase from xsdata.utils import collections diff --git a/tests/utils/test_namespaces.py b/tests/utils/test_namespaces.py index 2c371e298..6537348f8 100644 --- a/tests/utils/test_namespaces.py +++ b/tests/utils/test_namespaces.py @@ -1,4 +1,3 @@ -from typing import Dict from unittest import TestCase from xsdata.models.enums import Namespace @@ -19,7 +18,7 @@ class NamespacesTests(TestCase): def test_load_prefix(self): - ns_map: Dict = {} + ns_map: dict = {} self.assertEqual("ns0", load_prefix("a", ns_map)) self.assertEqual("ns0", load_prefix("a", ns_map)) self.assertEqual("ns0", load_prefix("a", ns_map)) @@ -34,7 +33,7 @@ def test_load_prefix(self): self.assertEqual(expected, ns_map) def test_generate_prefix(self): - ns_map: Dict = {} + ns_map: dict = {} self.assertEqual("ns0", generate_prefix("a", ns_map)) self.assertEqual("xs", generate_prefix(Namespace.XS.uri, ns_map)) self.assertEqual("soapenv", generate_prefix(Namespace.SOAP_ENV.uri, ns_map)) diff --git a/xsdata/cli.py b/xsdata/cli.py index a34a73d9e..3be1c8f43 100644 --- a/xsdata/cli.py +++ b/xsdata/cli.py @@ -2,8 +2,9 @@ import platform import sys import warnings +from collections.abc import Iterator from pathlib import Path -from typing import Any, Iterator +from typing import Any import click from click_default_group import DefaultGroup diff --git a/xsdata/codegen/container.py b/xsdata/codegen/container.py index ae706abc0..394e3dc37 100644 --- a/xsdata/codegen/container.py +++ b/xsdata/codegen/container.py @@ -1,4 +1,5 @@ -from typing import Callable, Dict, Iterator, List, Optional +from collections.abc import Iterator +from typing import Callable, Optional from xsdata.codegen.handlers import ( AddAttributeSubstitutions, @@ -72,7 +73,7 @@ def __init__(self, config: GeneratorConfig): """ super().__init__(config) self.step: int = 0 - self.processors: Dict[int, List] = { + self.processors: dict[int, list] = { Steps.UNGROUP: [ FlattenAttributeGroups(self), ], @@ -271,7 +272,7 @@ def reset(self, item: Class, qname: str): self.data[qname] = [c for c in self.data[qname] if c.ref != item.ref] self.add(item) - def set(self, items: List[Class]): + def set(self, items: list[Class]): """Set the list of classes to the container. Args: @@ -280,7 +281,7 @@ def set(self, items: List[Class]): self.data.clear() self.extend(items) - def extend(self, items: List[Class]): + def extend(self, items: list[Class]): """Add a list of classes to the container. Args: diff --git a/xsdata/codegen/handlers/add_attribute_substitutions.py b/xsdata/codegen/handlers/add_attribute_substitutions.py index 48cc6e27b..3ddcf37ee 100644 --- a/xsdata/codegen/handlers/add_attribute_substitutions.py +++ b/xsdata/codegen/handlers/add_attribute_substitutions.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Dict, List, Optional +from typing import Optional from xsdata.codegen.mixins import ContainerInterface, RelativeHandlerInterface from xsdata.codegen.models import Attr, AttrType, Class @@ -22,7 +22,7 @@ class AddAttributeSubstitutions(RelativeHandlerInterface): def __init__(self, container: ContainerInterface): super().__init__(container) - self.substitutions: Optional[Dict[str, List[Attr]]] = None + self.substitutions: Optional[dict[str, list[Attr]]] = None def process(self, target: Class): """Process the given class attrs for substitution groups. diff --git a/xsdata/codegen/handlers/create_compound_fields.py b/xsdata/codegen/handlers/create_compound_fields.py index 5ba308ffd..1356ba9ea 100644 --- a/xsdata/codegen/handlers/create_compound_fields.py +++ b/xsdata/codegen/handlers/create_compound_fields.py @@ -1,5 +1,4 @@ from collections import Counter -from typing import Dict, List, Set, Tuple from xsdata.codegen.mixins import ContainerInterface, RelativeHandlerInterface from xsdata.codegen.models import Attr, Class, Restrictions, get_restriction_choice @@ -50,7 +49,7 @@ def process(self, target: Class): self.calculate_choice_min_occurs(attrs) @classmethod - def calculate_choice_min_occurs(cls, attrs: List[Attr]): + def calculate_choice_min_occurs(cls, attrs: list[Attr]): """Calculate the min occurs restriction of the attrs. If that attr has a path that includes a xs:choice @@ -68,7 +67,7 @@ def calculate_choice_min_occurs(cls, attrs: List[Attr]): attr.restrictions.min_occurs = 0 @classmethod - def update_counters(cls, attr: Attr, counters: Dict): + def update_counters(cls, attr: Attr, counters: dict): """Update the counters dictionary with the attr min/max restrictions. This method builds a nested counters mapping per path. @@ -106,7 +105,7 @@ def update_counters(cls, attr: Attr, counters: Dict): counters["min"].append(attr.restrictions.min_occurs) counters["max"].append(attr.restrictions.max_occurs) - def group_fields(self, target: Class, attrs: List[Attr]): + def group_fields(self, target: Class, attrs: list[Attr]): """Group attributes into a new compound field. Args: @@ -121,7 +120,7 @@ def group_fields(self, target: Class, attrs: List[Attr]): names = [] substitutions = [] choices = [] - counters: Dict = {"min": [], "max": []} + counters: dict = {"min": [], "max": []} for attr in attrs: ClassUtils.remove_attribute(target, attr) @@ -147,7 +146,7 @@ def group_fields(self, target: Class, attrs: List[Attr]): ) target.attrs.insert(pos, compound_attr) - def sum_counters(self, counters: Dict) -> Tuple[List[int], List[int]]: + def sum_counters(self, counters: dict) -> tuple[list[int], list[int]]: """Sum the min/max occurrences for the compound attr. Args: @@ -171,8 +170,8 @@ def sum_counters(self, counters: Dict) -> Tuple[List[int], List[int]]: def choose_name( self, target: Class, - names: List[str], - substitutions: List[str], + names: list[str], + substitutions: list[str], ) -> str: """Choose a name for the compound attr. @@ -209,7 +208,7 @@ def choose_name( reserved = self.build_reserved_names(target, names) return ClassUtils.unique_name(name, reserved) - def build_reserved_names(self, target: Class, names: List[str]) -> Set[str]: + def build_reserved_names(self, target: Class, names: list[str]) -> set[str]: """Build a set of reserved attr names. The method will also check parent attrs. diff --git a/xsdata/codegen/handlers/create_wrapper_fields.py b/xsdata/codegen/handlers/create_wrapper_fields.py index b9dee7442..8258f70b1 100644 --- a/xsdata/codegen/handlers/create_wrapper_fields.py +++ b/xsdata/codegen/handlers/create_wrapper_fields.py @@ -1,4 +1,4 @@ -from typing import Optional, Tuple +from typing import Optional from xsdata.codegen.mixins import RelativeHandlerInterface from xsdata.codegen.models import Attr, Class @@ -61,7 +61,7 @@ def wrap_field(cls, source: Attr, attr: Attr, inner: bool): def find_source_attr( self, parent: Class, attr: Attr - ) -> Tuple[bool, Optional[Attr]]: + ) -> tuple[bool, Optional[Attr]]: """Find the source type for the given attr type instance. If it's a forward reference, look up the source in diff --git a/xsdata/codegen/handlers/designate_class_packages.py b/xsdata/codegen/handlers/designate_class_packages.py index 9a113291f..04718ce3f 100644 --- a/xsdata/codegen/handlers/designate_class_packages.py +++ b/xsdata/codegen/handlers/designate_class_packages.py @@ -1,8 +1,9 @@ import os import re from collections import defaultdict +from collections.abc import Iterable, Iterator from pathlib import Path -from typing import Iterable, Iterator, List, Optional, Set +from typing import Optional from urllib.parse import urlparse from toposort import toposort_flatten @@ -132,7 +133,7 @@ def group_by_namespace_clusters(self): module = classes[0].name self.assign(classes, ".".join(parts), module) - def sort_classes(self, qnames: Set[str]) -> List[Class]: + def sort_classes(self, qnames: set[str]) -> list[Class]: """Sort classes by their dependencies graph. Args: @@ -148,7 +149,7 @@ def sort_classes(self, qnames: Set[str]) -> List[Class]: } return [self.container.first(qname) for qname in toposort_flatten(edges)] - def strongly_connected_classes(self) -> Iterator[Set[str]]: + def strongly_connected_classes(self) -> Iterator[set[str]]: """Compute strongly connected classes of a directed graph. Returns: @@ -170,7 +171,7 @@ def assign(cls, classes: Iterable[Class], package: str, module: str): cls.assign(obj.inner, package, module) @classmethod - def group_common_paths(cls, paths: Iterable[str]) -> List[List[str]]: + def group_common_paths(cls, paths: Iterable[str]) -> list[list[str]]: """Group a list of file paths by their common paths. Args: @@ -198,7 +199,7 @@ def group_common_paths(cls, paths: Iterable[str]) -> List[List[str]]: return list(groups.values()) - def combine_ns_package(self, namespace: Optional[str]) -> List[str]: + def combine_ns_package(self, namespace: Optional[str]) -> list[str]: """Combine the output package with a namespace. You can add aliases to namespace uri with the diff --git a/xsdata/codegen/handlers/detect_circular_references.py b/xsdata/codegen/handlers/detect_circular_references.py index 4db8f725e..3ac6e0023 100644 --- a/xsdata/codegen/handlers/detect_circular_references.py +++ b/xsdata/codegen/handlers/detect_circular_references.py @@ -1,5 +1,3 @@ -from typing import Dict, List - from xsdata.codegen.mixins import ( ContainerInterface, RelativeHandlerInterface, @@ -21,7 +19,7 @@ class DetectCircularReferences(RelativeHandlerInterface): def __init__(self, container: ContainerInterface): super().__init__(container) - self.reference_types: Dict[int, List[AttrType]] = {} + self.reference_types: dict[int, list[AttrType]] = {} def process(self, target: Class): """Go through all the attr types and find circular references. @@ -38,7 +36,7 @@ def process(self, target: Class): for choice in attr.choices: self.process_types(choice.types, target.ref) - def process_types(self, types: List[AttrType], class_reference: int): + def process_types(self, types: list[AttrType], class_reference: int): """Go through the types and find circular references. Args: diff --git a/xsdata/codegen/handlers/disambiguate_choices.py b/xsdata/codegen/handlers/disambiguate_choices.py index 50018ebb5..5b3122d30 100644 --- a/xsdata/codegen/handlers/disambiguate_choices.py +++ b/xsdata/codegen/handlers/disambiguate_choices.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Iterator +from collections.abc import Iterator from xsdata.codegen.mixins import ContainerInterface, RelativeHandlerInterface from xsdata.codegen.models import Attr, AttrType, Class, Extension, Restrictions diff --git a/xsdata/codegen/handlers/filter_classes.py b/xsdata/codegen/handlers/filter_classes.py index 7dcc7a595..f11d95567 100644 --- a/xsdata/codegen/handlers/filter_classes.py +++ b/xsdata/codegen/handlers/filter_classes.py @@ -1,5 +1,3 @@ -from typing import List - from xsdata.codegen.mixins import ContainerHandlerInterface from xsdata.codegen.models import Class from xsdata.logger import logger @@ -25,7 +23,7 @@ def run(self): else: logger.warning("No global types exist, will generate all types.") - def filter_all_globals(self) -> List[Class]: + def filter_all_globals(self) -> list[Class]: """Filter all globals and any referenced types. This filter is trying to remove unused simple diff --git a/xsdata/codegen/handlers/merge_attributes.py b/xsdata/codegen/handlers/merge_attributes.py index a8d531dbe..a9846af62 100644 --- a/xsdata/codegen/handlers/merge_attributes.py +++ b/xsdata/codegen/handlers/merge_attributes.py @@ -1,5 +1,3 @@ -from typing import List - from xsdata.codegen.mixins import HandlerInterface from xsdata.codegen.models import Attr, Class from xsdata.codegen.utils import ClassUtils @@ -47,7 +45,7 @@ def merge_duplicate_attrs(cls, target: Class): Args: target: The target class instance """ - result: List[Attr] = [] + result: list[Attr] = [] for attr in target.attrs: pos = collections.find(result, attr) existing = result[pos] if pos > -1 else None diff --git a/xsdata/codegen/handlers/process_attributes_types.py b/xsdata/codegen/handlers/process_attributes_types.py index ba98bbb20..adba61e1f 100644 --- a/xsdata/codegen/handlers/process_attributes_types.py +++ b/xsdata/codegen/handlers/process_attributes_types.py @@ -1,4 +1,4 @@ -from typing import Dict, Optional +from typing import Optional from xsdata.codegen.mixins import ContainerInterface, RelativeHandlerInterface from xsdata.codegen.models import Attr, AttrType, Class @@ -22,7 +22,7 @@ class ProcessAttributeTypes(RelativeHandlerInterface): def __init__(self, container: ContainerInterface): super().__init__(container) - self.dependencies: Dict = {} + self.dependencies: dict = {} def process(self, target: Class): """Process the given class attrs and their types. diff --git a/xsdata/codegen/handlers/rename_duplicate_classes.py b/xsdata/codegen/handlers/rename_duplicate_classes.py index d026471e2..af7c9f68f 100644 --- a/xsdata/codegen/handlers/rename_duplicate_classes.py +++ b/xsdata/codegen/handlers/rename_duplicate_classes.py @@ -1,5 +1,3 @@ -from typing import Dict, List, Set - from xsdata.codegen.mixins import ContainerHandlerInterface, ContainerInterface from xsdata.codegen.models import ( Attr, @@ -27,15 +25,15 @@ class RenameDuplicateClasses(ContainerHandlerInterface): reserved: The reserved class names or qualified names """ - __slots__ = ("use_names", "renames", "merges", "reserved") + __slots__ = ("merges", "renames", "reserved", "use_names") def __init__(self, container: ContainerInterface): super().__init__(container) self.use_names = self.should_use_names() - self.renames: Dict[int, str] = {} - self.merges: Dict[int, int] = {} - self.reserved: Set[str] = set() + self.renames: dict[int, str] = {} + self.merges: dict[int, int] = {} + self.reserved: set[str] = set() def run(self): """Detect and resolve class name conflicts.""" @@ -68,7 +66,7 @@ def should_use_names(self) -> bool: or len(set(map(get_location, self.container))) == 1 ) - def merge_classes(self, classes: List[Class]): + def merge_classes(self, classes: list[Class]): """Remove the duplicate classes and update all references. Args: @@ -81,7 +79,7 @@ def merge_classes(self, classes: List[Class]): for item in classes: self.merges[item.ref] = replace - def rename_classes(self, classes: List[Class]): + def rename_classes(self, classes: list[Class]): """Rename the classes in the list. Cases: @@ -154,7 +152,7 @@ def next_qname(self, namespace: str, name: str) -> str: reserved.add(cmp) return qname - def get_reserved(self) -> Set[str]: + def get_reserved(self) -> set[str]: """Build the reserved names or qualified names of the container.""" if not self.reserved: getter = get_name if self.use_names else get_qname diff --git a/xsdata/codegen/handlers/sanitize_enumeration_class.py b/xsdata/codegen/handlers/sanitize_enumeration_class.py index edc392c25..36ad4cd48 100644 --- a/xsdata/codegen/handlers/sanitize_enumeration_class.py +++ b/xsdata/codegen/handlers/sanitize_enumeration_class.py @@ -1,4 +1,4 @@ -from typing import Any, List +from typing import Any from xsdata.codegen.mixins import RelativeHandlerInterface from xsdata.codegen.models import Class @@ -46,7 +46,7 @@ def flatten(self, target: Class): if len(target.attrs) != 1 or target.attrs[0].tag != Tag.UNION: return - enums: List[Any] = [] + enums: list[Any] = [] for attr_type in target.attrs[0].types: if attr_type.forward: enums.extend(target.inner) diff --git a/xsdata/codegen/handlers/unnest_inner_classes.py b/xsdata/codegen/handlers/unnest_inner_classes.py index 9f42cfcb5..2cb46dc73 100644 --- a/xsdata/codegen/handlers/unnest_inner_classes.py +++ b/xsdata/codegen/handlers/unnest_inner_classes.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import Iterator, List, Tuple +from collections.abc import Iterator from xsdata.codegen.mixins import RelativeHandlerInterface from xsdata.codegen.models import AttrType, Class @@ -52,7 +52,7 @@ def remove_orphan_inner_classes(cls, target: Class, promote_all: bool): target.inner.remove(inner) @classmethod - def find_forward_refs(cls, target: Class) -> Iterator[Tuple[AttrType, Class]]: + def find_forward_refs(cls, target: Class) -> Iterator[tuple[AttrType, Class]]: """Find all forward references for all inner classes. Args: @@ -89,7 +89,7 @@ def update_inner_class(cls, target: Class): target.local_type = True @classmethod - def update_types(cls, types: List[AttrType], qname: str): + def update_types(cls, types: list[AttrType], qname: str): """Search and replace forward references. Return the number changes. diff --git a/xsdata/codegen/handlers/update_attributes_effective_choice.py b/xsdata/codegen/handlers/update_attributes_effective_choice.py index 5e2940e9e..41d083b7d 100644 --- a/xsdata/codegen/handlers/update_attributes_effective_choice.py +++ b/xsdata/codegen/handlers/update_attributes_effective_choice.py @@ -1,5 +1,4 @@ from collections import defaultdict -from typing import List, Tuple from xsdata.codegen.mixins import HandlerInterface from xsdata.codegen.models import Attr, Class, get_restriction_choice @@ -70,7 +69,7 @@ def reset_symmetrical_choices(cls, target: Class): @classmethod def reset_effective_choice( cls, - paths: List[Tuple[str, int, int, int]], + paths: list[tuple[str, int, int, int]], index: int, max_occur: int, ): @@ -88,7 +87,7 @@ def reset_effective_choice( break @classmethod - def merge_attrs(cls, target: Class, groups: List[List[int]]) -> List[Attr]: + def merge_attrs(cls, target: Class, groups: list[list[int]]) -> list[Attr]: """Merge same name/tag/namespace attrs. Args: @@ -122,7 +121,7 @@ def merge_attrs(cls, target: Class, groups: List[List[int]]) -> List[Attr]: return attrs @classmethod - def group_repeating_attrs(cls, target: Class) -> List[List[int]]: + def group_repeating_attrs(cls, target: Class) -> list[list[int]]: """Create a list of indexes of the same attrs. Example: [ diff --git a/xsdata/codegen/handlers/vacuum_inner_classes.py b/xsdata/codegen/handlers/vacuum_inner_classes.py index 340d04c9b..552080d79 100644 --- a/xsdata/codegen/handlers/vacuum_inner_classes.py +++ b/xsdata/codegen/handlers/vacuum_inner_classes.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from xsdata.codegen.mixins import HandlerInterface from xsdata.codegen.models import AttrType, Class diff --git a/xsdata/codegen/handlers/validate_attributes_overrides.py b/xsdata/codegen/handlers/validate_attributes_overrides.py index ad7cf1381..b3f6e9960 100644 --- a/xsdata/codegen/handlers/validate_attributes_overrides.py +++ b/xsdata/codegen/handlers/validate_attributes_overrides.py @@ -1,5 +1,5 @@ import sys -from typing import Dict, List, Optional, Set +from typing import Optional from xsdata.codegen.mixins import RelativeHandlerInterface from xsdata.codegen.models import Attr, Class, get_slug @@ -36,8 +36,8 @@ def process(self, target: Class): def prohibit_parent_attrs( cls, target: Class, - explicit_attrs: Set[str], - base_attrs_map: Dict[str, List[Attr]], + explicit_attrs: set[str], + base_attrs_map: dict[str, list[Attr]], ): """Prepend prohibited parent attrs to the target class. @@ -61,7 +61,7 @@ def prohibit_parent_attrs( target.attrs.insert(0, attr_restricted) @classmethod - def validate_attrs(cls, target: Class, base_attrs_map: Dict[str, List[Attr]]): + def validate_attrs(cls, target: Class, base_attrs_map: dict[str, list[Attr]]): """Validate overriding attrs. Cases: @@ -99,7 +99,7 @@ def overrides(cls, a: Attr, b: Attr) -> bool: """ return a.xml_type == b.xml_type and a.namespace == b.namespace - def base_attrs_map(self, target: Class) -> Dict[str, List[Attr]]: + def base_attrs_map(self, target: Class) -> dict[str, list[Attr]]: """Create a mapping of qualified names to lists of parent attrs. Args: diff --git a/xsdata/codegen/handlers/validate_references.py b/xsdata/codegen/handlers/validate_references.py index de6dff404..5d00beb38 100644 --- a/xsdata/codegen/handlers/validate_references.py +++ b/xsdata/codegen/handlers/validate_references.py @@ -1,4 +1,4 @@ -from typing import Optional, Set +from typing import Optional from xsdata.codegen.exceptions import CodegenError from xsdata.codegen.mixins import ContainerHandlerInterface @@ -36,7 +36,7 @@ def validate_unique_qualified_names(self): def validate_unique_instances(self): """Validate all codegen instances are unique.""" - references: Set[int] = set() + references: set[int] = set() for item in self.container: item_references = {id(child) for child in item.children()} if item_references.intersection(references): diff --git a/xsdata/codegen/mappers/definitions.py b/xsdata/codegen/mappers/definitions.py index c3402c381..715a6652d 100644 --- a/xsdata/codegen/mappers/definitions.py +++ b/xsdata/codegen/mappers/definitions.py @@ -1,5 +1,6 @@ import itertools -from typing import Dict, Iterator, List, Optional, Tuple +from collections.abc import Iterator +from typing import Optional from xsdata.codegen.models import Attr, AttrType, Class, Restrictions, Status from xsdata.formats.dataclass.models.generics import AnyElement @@ -27,7 +28,7 @@ class DefinitionsMapper: """ @classmethod - def map(cls, definitions: Definitions) -> List[Class]: + def map(cls, definitions: Definitions) -> list[Class]: """Main entrypoint for this mapper. Iterates over their services and their ports and build @@ -74,7 +75,7 @@ def map_binding( definitions: Definitions, binding: Binding, port_type: PortType, - config: Dict, + config: dict, ) -> Iterator[Class]: """Map binding operations into binding and service classes. @@ -105,7 +106,7 @@ def map_binding_operation( definitions: Definitions, binding_operation: BindingOperation, port_type_operation: PortTypeOperation, - config: Dict, + config: dict, name: str, ) -> Iterator[Class]: """Map a binding operation to a service and binding classes. @@ -185,7 +186,7 @@ def map_binding_operation_messages( Yields: An iterator of class instances. """ - messages: List[Tuple[str, BindingMessage, PortTypeMessage, Optional[str]]] = [] + messages: list[tuple[str, BindingMessage, PortTypeMessage, Optional[str]]] = [] if binding_operation.input: messages.append( @@ -235,11 +236,11 @@ def build_envelope_fault( port_type_operation: The port type operation instance target: The target class instance """ - ns_map: Dict = {} + ns_map: dict = {} body = next(inner for inner in target.inner if inner.name == "Body") fault_class = cls.build_inner_class(body, "Fault", target.namespace) - detail_attrs: List[Attr] = [] + detail_attrs: list[Attr] = [] for fault in port_type_operation.faults: message = definitions.find_message(text.suffix(fault.message)) detail_attrs.extend(cls.build_parts_attributes(message.parts, ns_map)) @@ -417,7 +418,7 @@ def map_port_type_message( @classmethod def map_binding_message_parts( - cls, definitions: Definitions, message: str, extended: AnyElement, ns_map: Dict + cls, definitions: Definitions, message: str, extended: AnyElement, ns_map: dict ) -> Iterator[Attr]: """Find a Message instance and map its parts to attrs. @@ -450,7 +451,7 @@ def map_binding_message_parts( yield from cls.build_parts_attributes(message_parts, ns_map) @classmethod - def build_parts_attributes(cls, parts: List[Part], ns_map: Dict) -> Iterator[Attr]: + def build_parts_attributes(cls, parts: list[Part], ns_map: dict) -> Iterator[Attr]: """Build attributes for the given list of parts. Args: @@ -482,7 +483,7 @@ def build_parts_attributes(cls, parts: List[Part], ns_map: Dict) -> Iterator[Att yield cls.build_attr(name, type_qname, namespace=namespace, native=native) @classmethod - def operation_namespace(cls, config: Dict) -> Optional[str]: + def operation_namespace(cls, config: dict) -> Optional[str]: """Return the operation namespace by the operation transport. Args: @@ -499,7 +500,7 @@ def operation_namespace(cls, config: Dict) -> Optional[str]: return namespace @classmethod - def attributes(cls, elements: Iterator[AnyElement]) -> Dict: + def attributes(cls, elements: Iterator[AnyElement]) -> dict: """Return all attributes from all extended elements as a dictionary. Args: diff --git a/xsdata/codegen/mappers/dict.py b/xsdata/codegen/mappers/dict.py index 8aae9b09d..f2e069cd6 100644 --- a/xsdata/codegen/mappers/dict.py +++ b/xsdata/codegen/mappers/dict.py @@ -1,5 +1,5 @@ import sys -from typing import Any, Dict, List +from typing import Any from xsdata.codegen.mappers.mixins import RawDocumentMapper from xsdata.codegen.models import AttrType, Class @@ -14,7 +14,7 @@ class DictMapper(RawDocumentMapper): """ @classmethod - def map(cls, data: Dict, name: str, location: str) -> List[Class]: + def map(cls, data: dict, name: str, location: str) -> list[Class]: """Map a dictionary to classes. Args: @@ -29,7 +29,7 @@ def map(cls, data: Dict, name: str, location: str) -> List[Class]: return list(ClassUtils.flatten(target, f"{location}/{name}")) @classmethod - def build_class(cls, data: Dict, name: str) -> Class: + def build_class(cls, data: dict, name: str) -> Class: """Build a class from a data dictionary. Args: diff --git a/xsdata/codegen/mappers/dtd.py b/xsdata/codegen/mappers/dtd.py index 016ccab1f..7bcc7255a 100644 --- a/xsdata/codegen/mappers/dtd.py +++ b/xsdata/codegen/mappers/dtd.py @@ -1,5 +1,6 @@ import sys -from typing import Any, Dict, Iterator, List, Optional +from collections.abc import Iterator +from typing import Any, Optional from xsdata.codegen.models import Attr, AttrType, Class, Extension, Restrictions from xsdata.models.dtd import ( @@ -228,7 +229,7 @@ def build_content_tree(cls, target: Class, content: DtdContent, **kwargs: Any): cls.build_content(target, content.right, **kwargs) @classmethod - def build_occurs(cls, occur: DtdContentOccur) -> Dict: + def build_occurs(cls, occur: DtdContentOccur) -> dict: """Calculate min/max occurs from the dtd content occur instance. Args: @@ -306,7 +307,7 @@ def build_value(cls, target: Class, restrictions: Restrictions): target.attrs.append(attr) @classmethod - def build_enumeration(cls, target: Class, name: str, values: List[str]): + def build_enumeration(cls, target: Class, name: str, values: list[str]): """Build a nested enumeration class from the given values list. Args: diff --git a/xsdata/codegen/mappers/element.py b/xsdata/codegen/mappers/element.py index a89c9fda8..cf56987a9 100644 --- a/xsdata/codegen/mappers/element.py +++ b/xsdata/codegen/mappers/element.py @@ -1,5 +1,5 @@ from collections import defaultdict -from typing import List, Optional +from typing import Optional from xsdata.codegen.mappers.mixins import RawDocumentMapper from xsdata.codegen.models import AttrType, Class @@ -17,7 +17,7 @@ class ElementMapper(RawDocumentMapper): """ @classmethod - def map(cls, element: AnyElement, location: str) -> List[Class]: + def map(cls, element: AnyElement, location: str) -> list[Class]: """Map schema children elements to classes. Args: @@ -138,7 +138,7 @@ def build_text(cls, target: Class, element: AnyElement): target.mixed = True @classmethod - def sequential_groups(cls, element: AnyElement) -> List[List[int]]: + def sequential_groups(cls, element: AnyElement) -> list[list[int]]: """Identify sequential groups of repeating attributes. Args: @@ -151,7 +151,7 @@ def sequential_groups(cls, element: AnyElement) -> List[List[int]]: return list(collections.connected_components(groups)) @classmethod - def group_repeating_attrs(cls, element: AnyElement) -> List[List[int]]: + def group_repeating_attrs(cls, element: AnyElement) -> list[list[int]]: """Group repeating children in the given generic element. Args: @@ -165,7 +165,7 @@ def group_repeating_attrs(cls, element: AnyElement) -> List[List[int]]: if isinstance(child, AnyElement) and child.qname: counters[child.qname].append(index) - groups: List[List[int]] = [] + groups: list[list[int]] = [] if len(counters) > 1: groups.extend( list(range(x[0], x[-1] + 1)) for x in counters.values() if len(x) > 1 diff --git a/xsdata/codegen/mappers/schema.py b/xsdata/codegen/mappers/schema.py index 257bfeb4e..a1d564036 100644 --- a/xsdata/codegen/mappers/schema.py +++ b/xsdata/codegen/mappers/schema.py @@ -1,4 +1,5 @@ -from typing import Dict, Iterator, List, Optional, Tuple +from collections.abc import Iterator +from typing import Optional from xsdata.codegen.models import Attr, AttrType, Class, Extension, Restrictions from xsdata.models.enums import DataType, Tag @@ -25,7 +26,7 @@ class SchemaMapper: """ @classmethod - def map(cls, schema: Schema) -> List[Class]: + def map(cls, schema: Schema) -> list[Class]: """Map schema children elements to classes. Args: @@ -45,7 +46,7 @@ def map(cls, schema: Schema) -> List[Class]: ] @classmethod - def root_elements(cls, schema: Schema) -> Iterator[Tuple[str, ElementBase]]: + def root_elements(cls, schema: Schema) -> Iterator[tuple[str, ElementBase]]: """Return the schema root elements. Qualified Elements: @@ -121,7 +122,7 @@ def build_substitutions( cls, obj: ElementBase, target_namespace: Optional[str], - ) -> List[str]: + ) -> list[str]: """Builds a list of qualified substitution group names. Args: @@ -199,7 +200,7 @@ def element_children( cls, obj: ElementBase, parent_restrictions: Restrictions, - ) -> Iterator[Tuple[ElementBase, Restrictions]]: + ) -> Iterator[tuple[ElementBase, Restrictions]]: """Recursively find and return all child elements. Args: @@ -289,7 +290,7 @@ def build_class_extension( tag: str, target: Class, name: str, - restrictions: Dict, + restrictions: dict, ) -> Extension: """Create a reference extension for the target class. @@ -345,7 +346,7 @@ def build_class_attribute( ) @classmethod - def build_attr_types(cls, target: Class, obj: ElementBase) -> List[AttrType]: + def build_attr_types(cls, target: Class, obj: ElementBase) -> list[AttrType]: """Convert the element types and inner types to an attr types. Args: diff --git a/xsdata/codegen/mixins.py b/xsdata/codegen/mixins.py index 61d14805a..eed39dab7 100644 --- a/xsdata/codegen/mixins.py +++ b/xsdata/codegen/mixins.py @@ -1,5 +1,6 @@ import abc -from typing import Callable, Dict, Iterator, List, Optional +from collections.abc import Iterator +from typing import Callable, Optional from xsdata.codegen.models import Attr, Class from xsdata.models.config import GeneratorConfig @@ -17,7 +18,7 @@ class ContainerInterface(abc.ABC): def __init__(self, config: GeneratorConfig): self.config = config - self.data: Dict[str, List[Class]] = {} + self.data: dict[str, list[Class]] = {} @abc.abstractmethod def __iter__(self) -> Iterator[Class]: @@ -89,7 +90,7 @@ def remove(self, *items: Class): """ @abc.abstractmethod - def extend(self, items: List[Class]): + def extend(self, items: list[Class]): """Add a list of classes to the container. Args: @@ -106,7 +107,7 @@ def reset(self, item: Class, qname: str): """ @abc.abstractmethod - def set(self, items: List[Class]): + def set(self, items: list[Class]): """Set the list of classes to the container. Args: @@ -140,7 +141,7 @@ class RelativeHandlerInterface(HandlerInterface, abc.ABC): def __init__(self, container: ContainerInterface): self.container = container - def base_attrs(self, target: Class) -> List[Attr]: + def base_attrs(self, target: Class) -> list[Attr]: """Return a list of all parent attrs recursively. Args: @@ -150,7 +151,7 @@ def base_attrs(self, target: Class) -> List[Attr]: A list of attr instances. """ - attrs: List[Attr] = [] + attrs: list[Attr] = [] for extension in target.extensions: base = self.container.find(extension.type.qname) diff --git a/xsdata/codegen/models.py b/xsdata/codegen/models.py index f8b28444b..8197ebf03 100644 --- a/xsdata/codegen/models.py +++ b/xsdata/codegen/models.py @@ -2,9 +2,10 @@ import operator import sys import unicodedata +from collections.abc import Iterator from dataclasses import asdict, dataclass, field, fields, replace from enum import IntEnum -from typing import Any, Dict, Iterator, List, Optional, Tuple, Type, TypeVar +from typing import Any, Optional, TypeVar from xsdata.codegen.exceptions import CodegenError from xsdata.formats.converter import converter @@ -98,7 +99,7 @@ class Restrictions(CodegenModel): choice: Optional[int] = field(default=None, compare=False) group: Optional[int] = field(default=None) process_contents: Optional[str] = field(default=None) - path: List[Tuple[str, int, int, int]] = field(default_factory=list) + path: list[tuple[str, int, int, int]] = field(default_factory=list) @property def is_list(self) -> bool: @@ -155,7 +156,7 @@ def merge(self, source: "Restrictions"): if self.max_occurs is None and source.max_occurs is not None: self.max_occurs = source.max_occurs - def asdict(self, types: Optional[List[Type]] = None) -> Dict: + def asdict(self, types: Optional[list[type]] = None) -> dict: """Return the initialized only properties as a dictionary. Skip None or implied values, and optionally use the @@ -294,8 +295,8 @@ class Attr(CodegenModel): default: Optional[str] = field(default=None, compare=False) fixed: bool = field(default=False, compare=False) mixed: bool = field(default=False, compare=False) - types: List[AttrType] = field(default_factory=list, compare=False) - choices: List["Attr"] = field(default_factory=list, compare=False) + types: list[AttrType] = field(default_factory=list, compare=False) + choices: list["Attr"] = field(default_factory=list, compare=False) namespace: Optional[str] = field(default=None) help: Optional[str] = field(default=None, compare=False) restrictions: Restrictions = field(default_factory=Restrictions, compare=False) @@ -420,7 +421,7 @@ def is_any_type(self) -> bool: return any(tp is object for tp in self.get_native_types()) @property - def native_types(self) -> List[Type]: + def native_types(self) -> list[type]: """Return a list of all the builtin data types.""" return list(set(self.get_native_types())) @@ -441,7 +442,7 @@ def xml_type(self) -> Optional[str]: """Return the xml type this attribute is mapped to.""" return xml_type_map.get(self.tag) - def get_native_types(self) -> Iterator[Type]: + def get_native_types(self) -> Iterator[type]: """Yield an iterator of all the native attr types.""" for tp in self.types: datatype = tp.datatype @@ -531,11 +532,11 @@ class Class(CodegenModel): meta_name: Optional[str] = field(default=None) default: Any = field(default=None, compare=False) fixed: bool = field(default=False, compare=False) - substitutions: List[str] = field(default_factory=list) - extensions: List[Extension] = field(default_factory=list) - attrs: List[Attr] = field(default_factory=list) - inner: List["Class"] = field(default_factory=list) - ns_map: Dict = field(default_factory=dict) + substitutions: list[str] = field(default_factory=list) + extensions: list[Extension] = field(default_factory=list) + attrs: list[Attr] = field(default_factory=list) + inner: list["Class"] = field(default_factory=list) + ns_map: dict = field(default_factory=dict) parent: Optional["Class"] = field(default=None, compare=False) @property @@ -663,7 +664,7 @@ def types(self) -> Iterator[AttrType]: for _, tp in self.types_with_parents(): yield tp - def types_with_parents(self) -> Iterator[Tuple[CodegenModel, AttrType]]: + def types_with_parents(self) -> Iterator[tuple[CodegenModel, AttrType]]: """Yields all class types with their parent codegen instance.""" for ext in self.extensions: yield ext, ext.type @@ -685,15 +686,13 @@ def children(self) -> Iterator[CodegenModel]: yield attr yield attr.restrictions - for tp in attr.types: - yield tp + yield from attr.types for choice in attr.choices: yield choice yield choice.restrictions - for tp in choice.types: - yield tp + yield from choice.types for ext in self.extensions: yield ext @@ -714,7 +713,7 @@ def has_forward_ref(self) -> bool: return any(inner.has_forward_ref() for inner in self.inner) - def parent_names(self) -> List[str]: + def parent_names(self) -> list[str]: """Return the outer class names.""" result = [] target = self.parent diff --git a/xsdata/codegen/parsers/definitions.py b/xsdata/codegen/parsers/definitions.py index 1cfc7f876..c9778f146 100644 --- a/xsdata/codegen/parsers/definitions.py +++ b/xsdata/codegen/parsers/definitions.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, List, Optional +from typing import Any, Optional from xsdata.codegen.parsers.schema import SchemaParser from xsdata.formats.dataclass.parsers.bases import Parsed @@ -14,8 +14,8 @@ class DefinitionsParser(SchemaParser): def end( self, - queue: List[XmlNode], - objects: List[Parsed], + queue: list[XmlNode], + objects: list[Parsed], qname: str, text: Optional[str], tail: Optional[str], diff --git a/xsdata/codegen/parsers/dtd.py b/xsdata/codegen/parsers/dtd.py index fa6105f4d..6fd2e1da5 100644 --- a/xsdata/codegen/parsers/dtd.py +++ b/xsdata/codegen/parsers/dtd.py @@ -1,5 +1,5 @@ import io -from typing import Any, Dict, List, Optional +from typing import Any, Optional from xsdata.exceptions import ParserError from xsdata.models.dtd import ( @@ -106,7 +106,7 @@ def build_attribute(cls, attribute: Any) -> DtdAttribute: ) @classmethod - def build_ns_map(cls, prefix: str, attributes: List[DtdAttribute]) -> Dict: + def build_ns_map(cls, prefix: str, attributes: list[DtdAttribute]) -> dict: """Build the dtd element namespace prefix-URI map. It also adds common namespaces like xs, xsi, xlink and xml. diff --git a/xsdata/codegen/parsers/schema.py b/xsdata/codegen/parsers/schema.py index 6513c32d8..c84783b01 100644 --- a/xsdata/codegen/parsers/schema.py +++ b/xsdata/codegen/parsers/schema.py @@ -1,6 +1,6 @@ import sys from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Type, Union +from typing import Any, Optional, Union from urllib.parse import urljoin from xsdata.formats.dataclass.parsers.bases import Parsed @@ -37,7 +37,7 @@ class SchemaParser(UserXmlParser): location: Optional[str] = field(default=None) target_namespace: Optional[str] = field(default=None) index: int = field(default_factory=int, init=False) - indices: List[int] = field(default_factory=list, init=False) + indices: list[int] = field(default_factory=list, init=False) element_form: Optional[str] = field(default=None, init=False) attribute_form: Optional[str] = field(default=None, init=False) default_attributes: Optional[str] = field(default=None, init=False) @@ -47,12 +47,12 @@ class SchemaParser(UserXmlParser): def start( self, - clazz: Optional[Type[T]], - queue: List[XmlNode], - objects: List[Parsed], + clazz: Optional[type[T]], + queue: list[XmlNode], + objects: list[Parsed], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, ): """Build and queue the XmlNode for the starting element. @@ -73,8 +73,8 @@ def start( def end( self, - queue: List[XmlNode], - objects: List[Parsed], + queue: list[XmlNode], + objects: list[Parsed], qname: str, text: Optional[str], tail: Optional[str], @@ -102,7 +102,7 @@ def end( return obj - def start_schema(self, attrs: Dict[str, str]): + def start_schema(self, attrs: dict[str, str]): """Start schema element entrypoint. Store the element/attribute default forms and the @@ -361,7 +361,7 @@ def has_elements(cls, obj: ElementBase) -> bool: ) @classmethod - def set_namespace_map(cls, obj: Any, ns_map: Optional[Dict]): + def set_namespace_map(cls, obj: Any, ns_map: Optional[dict]): """Add common namespaces like xml, xsi, xlink if they are missing. These prefixes are implied and we need to support them. diff --git a/xsdata/codegen/resolver.py b/xsdata/codegen/resolver.py index 58a7a82e2..0b450372a 100644 --- a/xsdata/codegen/resolver.py +++ b/xsdata/codegen/resolver.py @@ -1,6 +1,5 @@ import logging import re -from typing import Dict, List from toposort import toposort_flatten @@ -28,16 +27,16 @@ class DependenciesResolver: """ - __slots__ = "registry", "aliases", "imports", "class_list", "class_map" + __slots__ = "aliases", "class_list", "class_map", "imports", "registry" - def __init__(self, registry: Dict[str, str]): + def __init__(self, registry: dict[str, str]): self.registry = registry - self.aliases: Dict[str, str] = {} - self.imports: List[Import] = [] - self.class_list: List[str] = [] - self.class_map: Dict[str, Class] = {} + self.aliases: dict[str, str] = {} + self.imports: list[Import] = [] + self.class_list: list[str] = [] + self.class_map: dict[str, Class] = {} - def process(self, classes: List[Class]): + def process(self, classes: list[Class]): """Resolve the dependencies for the given class list. Reset previously resolved imports and aliases. @@ -51,11 +50,11 @@ def process(self, classes: List[Class]): self.class_list = self.create_class_list(classes) self.resolve_imports() - def sorted_imports(self) -> List[Import]: + def sorted_imports(self) -> list[Import]: """Return a new sorted by name list of import instances.""" return sorted(self.imports, key=lambda x: x.name) - def sorted_classes(self) -> List[Class]: + def sorted_classes(self) -> list[Class]: """Apply aliases and return the sorted the generated class list.""" result = [] for name in self.class_list: @@ -102,7 +101,7 @@ def set_aliases(self): self.aliases = {imp.qname: imp.alias for imp in self.imports if imp.alias} @classmethod - def resolve_conflicts(cls, imports: List[Import], protected: set): + def resolve_conflicts(cls, imports: list[Import], protected: set): """Find naming conflicts between imports and generate aliases. Example: @@ -142,17 +141,17 @@ def get_class_module(self, qname: str) -> str: raise CodegenError("Failed to resolve dependency", qname=qname) return self.registry[qname] - def import_classes(self) -> List[str]: + def import_classes(self) -> list[str]: """Return a list of class qnames that need to be imported.""" return [qname for qname in self.class_list if qname not in self.class_map] @staticmethod - def create_class_list(classes: List[Class]) -> List[str]: + def create_class_list(classes: list[Class]) -> list[str]: """Use topology sort to return a flat list for all the dependencies.""" return toposort_flatten({obj.qname: set(obj.dependencies()) for obj in classes}) @staticmethod - def create_class_map(classes: List[Class]) -> Dict[str, Class]: + def create_class_map(classes: list[Class]) -> dict[str, Class]: """Index the list of classes by their qualified names. Raises: @@ -161,7 +160,7 @@ def create_class_map(classes: List[Class]) -> Dict[str, Class]: Returns: A qname-class map. """ - result: Dict[str, Class] = {} + result: dict[str, Class] = {} for obj in classes: if obj.qname in result: raise CodegenError("Duplicate class during resolve", qname=obj.qname) diff --git a/xsdata/codegen/stopwatch.py b/xsdata/codegen/stopwatch.py index 6ac3b4c96..2a93c6aae 100644 --- a/xsdata/codegen/stopwatch.py +++ b/xsdata/codegen/stopwatch.py @@ -1,7 +1,6 @@ from collections import defaultdict from contextlib import contextmanager from time import perf_counter_ns -from typing import Dict, List @contextmanager @@ -13,4 +12,4 @@ def stopwatch(name: str): stopwatches[name].append(stop_time - start_time) -stopwatches: Dict[str, List[int]] = defaultdict(list) +stopwatches: dict[str, list[int]] = defaultdict(list) diff --git a/xsdata/codegen/transformer.py b/xsdata/codegen/transformer.py index fb1e59998..4f22ade11 100644 --- a/xsdata/codegen/transformer.py +++ b/xsdata/codegen/transformer.py @@ -6,7 +6,7 @@ import tempfile from collections import defaultdict from pathlib import Path -from typing import Callable, Dict, List, NamedTuple, Optional, Tuple +from typing import Callable, NamedTuple, Optional from toposort import CircularDependencyError @@ -108,15 +108,15 @@ class ResourceTransformer: preloaded: A uri/content map used as cache """ - __slots__ = ("config", "classes", "processed", "preloaded") + __slots__ = ("classes", "config", "preloaded", "processed") def __init__(self, config: GeneratorConfig): self.config = config - self.classes: List[Class] = [] - self.processed: List[str] = [] - self.preloaded: Dict = {} + self.classes: list[Class] = [] + self.processed: list[str] = [] + self.preloaded: dict = {} - def process(self, uris: List[str], cache: bool = False): + def process(self, uris: list[str], cache: bool = False): """Process a list of resolved URI strings. Args: @@ -148,7 +148,7 @@ def process(self, uris: List[str], cache: bool = False): for name, times in stopwatches.items(): logger.debug(f"{name} - {sum(times) / 1e9}s") - def process_sources(self, uris: List[str]): + def process_sources(self, uris: list[str]): """Process a list of resolved URI strings. Load the source URI strings and map them to codegen @@ -168,7 +168,7 @@ def process_sources(self, uris: List[str]): self.process_xml_documents(sources[TYPE_XML]) self.process_json_documents(sources[TYPE_JSON]) - def process_definitions(self, uris: List[str]): + def process_definitions(self, uris: list[str]): """Process a list of wsdl resources. Args: @@ -186,7 +186,7 @@ def process_definitions(self, uris: List[str]): collections.apply(definitions.schemas, self.convert_schema) self.convert_definitions(definitions) - def process_schemas(self, uris: List[str]): + def process_schemas(self, uris: list[str]): """Process a list of xsd resources. Args: @@ -195,13 +195,13 @@ def process_schemas(self, uris: List[str]): for uri in uris: self.process_schema(uri) - def process_dtds(self, uris: List[str]): + def process_dtds(self, uris: list[str]): """Process a list of dtd resources. Args: uris: A list of dtd URI strings to process """ - classes: List[Class] = [] + classes: list[Class] = [] for uri in uris: input_stream = self.load_resource(uri) @@ -225,7 +225,7 @@ def process_schema(self, uri: str, namespace: Optional[str] = None): if schema: self.convert_schema(schema) - def process_xml_documents(self, uris: List[str]): + def process_xml_documents(self, uris: list[str]): """Process a list of xml resources. Args: @@ -243,7 +243,7 @@ def process_xml_documents(self, uris: List[str]): self.classes.extend(ClassUtils.reduce_classes(classes)) - def process_json_documents(self, uris: List[str]): + def process_json_documents(self, uris: list[str]): """Process a list of json resources. Args: @@ -305,7 +305,7 @@ def convert_definitions(self, definitions: Definitions): """Convert a definitions instance to codegen classes.""" self.classes.extend(DefinitionsMapper.map(definitions)) - def generate_classes(self, schema: Schema) -> List[Class]: + def generate_classes(self, schema: Schema) -> list[Class]: """Convert the given schema instance to a list of classes.""" uri = schema.location logger.info("Compiling schema %s", uri or "...") @@ -409,14 +409,14 @@ def classify_resource(self, uri: str) -> int: return TYPE_UNKNOWN - def analyze_classes(self, classes: List[Class]) -> List[Class]: + def analyze_classes(self, classes: list[Class]) -> list[Class]: """Analyzer the given class list and return the final list of classes.""" container = ClassContainer(config=self.config) container.extend(classes) container.process() return list(container) - def count_classes(self, classes: List[Class]) -> Tuple[int, int]: + def count_classes(self, classes: list[Class]) -> tuple[int, int]: """Return a tuple of counters for the main and inner classes. Args: @@ -433,7 +433,7 @@ def count_classes(self, classes: List[Class]) -> Tuple[int, int]: return main, inner @classmethod - def get_cache_file(cls, uris: List[str]) -> Path: + def get_cache_file(cls, uris: list[str]) -> Path: """Return the cache path for the raw mapped classes. Args: diff --git a/xsdata/codegen/utils.py b/xsdata/codegen/utils.py index 616c48300..89be0d90a 100644 --- a/xsdata/codegen/utils.py +++ b/xsdata/codegen/utils.py @@ -1,6 +1,7 @@ import sys from collections import deque -from typing import Deque, Iterator, List, Optional, Set +from collections.abc import Iterator +from typing import Optional from xsdata.codegen.exceptions import CodegenError from xsdata.codegen.models import ( @@ -259,7 +260,7 @@ def flatten(cls, target: Class, location: str) -> Iterator[Class]: yield target @classmethod - def reduce_classes(cls, classes: List[Class]) -> List[Class]: + def reduce_classes(cls, classes: list[Class]) -> list[Class]: """Find duplicate classes and attrs and reduce them. Args: @@ -280,7 +281,7 @@ def reduce_classes(cls, classes: List[Class]) -> List[Class]: return result @classmethod - def reduce_attributes(cls, classes: List[Class]) -> List[Attr]: + def reduce_attributes(cls, classes: list[Class]) -> list[Attr]: """Find and merge duplicate attrs from the given class list. Args: @@ -309,7 +310,7 @@ def reduce_attributes(cls, classes: List[Class]) -> List[Attr]: return result @classmethod - def sorted_attrs(cls, classes: List[Class]) -> List[Attr]: + def sorted_attrs(cls, classes: list[Class]) -> list[Attr]: """Sort and return the attrs from all the class list. The list contains duplicate classes, the method tries @@ -321,7 +322,7 @@ def sorted_attrs(cls, classes: List[Class]) -> List[Attr]: Returns: A list of sorted duplicate attr instances. """ - attrs: List[Attr] = [] + attrs: list[Attr] = [] classes.sort(key=lambda x: len(x.attrs), reverse=True) for obj in classes: @@ -410,7 +411,7 @@ def rename_attribute_by_preference(cls, a: Attr, b: Attr): change.name = f"{change.name}_{change.tag}" @classmethod - def rename_attributes_by_index(cls, attrs: List[Attr], rename: List[Attr]): + def rename_attributes_by_index(cls, attrs: list[Attr], rename: list[Attr]): """Append the next available index number to all the rename attr names. Args: @@ -423,7 +424,7 @@ def rename_attributes_by_index(cls, attrs: List[Attr], rename: List[Attr]): rename[index].name = cls.unique_name(name, reserved) @classmethod - def unique_name(cls, name: str, reserved: Set[str]) -> str: + def unique_name(cls, name: str, reserved: set[str]) -> str: """Append the next available index number to the name. Args: @@ -455,7 +456,7 @@ def cleanup_class(cls, target: Class): attr.types = cls.filter_types(attr.types) @classmethod - def filter_types(cls, types: List[AttrType]) -> List[AttrType]: + def filter_types(cls, types: list[AttrType]) -> list[AttrType]: """Remove duplicate and invalid types. Invalid: @@ -500,8 +501,8 @@ def find_nested(cls, target: Class, qname: str) -> Class: Returns: The nested class instance. """ - queue: Deque[Class] = deque() - visited: Set[int] = set() + queue: deque[Class] = deque() + visited: set[int] = set() if target.inner: queue.extend(target.inner) diff --git a/xsdata/codegen/validator.py b/xsdata/codegen/validator.py index b191daa0f..f3750e36e 100644 --- a/xsdata/codegen/validator.py +++ b/xsdata/codegen/validator.py @@ -1,4 +1,4 @@ -from typing import List, Optional +from typing import Optional from xsdata.codegen.mixins import ContainerInterface from xsdata.codegen.models import Attr, Class, Extension, get_tag @@ -42,7 +42,7 @@ def process(self): if len(classes) > 1: self.merge_global_types(classes) - def remove_invalid_classes(self, classes: List[Class]): + def remove_invalid_classes(self, classes: list[Class]): """Remove classes with undefined extensions. Args: @@ -58,7 +58,7 @@ def is_invalid(ext: Extension) -> bool: classes.remove(target) @classmethod - def handle_duplicate_types(cls, classes: List[Class]): + def handle_duplicate_types(cls, classes: list[Class]): """Find and handle duplicate classes. If a class is defined more than once, keep either @@ -115,7 +115,7 @@ def merge_redefined_type(cls, source: Class, target: Class): ClassUtils.copy_group_attributes(source, target, circular_group) @classmethod - def select_winner(cls, candidates: List[Class]) -> int: + def select_winner(cls, candidates: list[Class]) -> int: """From a list of classes select which class index will remain. Classes that were extracted from in xs:override/xs:redefined @@ -170,7 +170,7 @@ class with the same qualified name. We need to locate return ClassUtils.find_attr(target, target.name) @classmethod - def merge_global_types(cls, classes: List[Class]): + def merge_global_types(cls, classes: list[Class]): """Merge parent-child global types. Conditions diff --git a/xsdata/codegen/writer.py b/xsdata/codegen/writer.py index 198d5ed1e..08004c1bf 100644 --- a/xsdata/codegen/writer.py +++ b/xsdata/codegen/writer.py @@ -1,4 +1,4 @@ -from typing import ClassVar, Dict, List, Type +from typing import ClassVar from xsdata.codegen.exceptions import CodegenError from xsdata.codegen.models import Class @@ -20,14 +20,14 @@ class CodeWriter: __slots__ = "generator" - generators: ClassVar[Dict[str, Type[AbstractGenerator]]] = { + generators: ClassVar[dict[str, type[AbstractGenerator]]] = { "dataclasses": DataclassGenerator, } def __init__(self, generator: AbstractGenerator): self.generator = generator - def write(self, classes: List[Class]): + def write(self, classes: list[Class]): """Write the classes to the designated modules. The classes may be written in the same module or @@ -68,7 +68,7 @@ def from_config(cls, config: GeneratorConfig) -> "CodeWriter": return cls(generator=generator_class(config)) @classmethod - def register_generator(cls, name: str, clazz: Type[AbstractGenerator]): + def register_generator(cls, name: str, clazz: type[AbstractGenerator]): """Register a generator by name. Args: diff --git a/xsdata/formats/converter.py b/xsdata/formats/converter.py index deab184f6..a9f156952 100644 --- a/xsdata/formats/converter.py +++ b/xsdata/formats/converter.py @@ -3,6 +3,7 @@ import binascii import math import re +from collections.abc import Sequence from contextlib import suppress from datetime import date, datetime, time from decimal import Decimal, InvalidOperation @@ -10,12 +11,7 @@ from typing import ( Any, Callable, - Dict, - List, Optional, - Sequence, - Tuple, - Type, Union, cast, ) @@ -65,7 +61,7 @@ def serialize(self, value: Any, **kwargs: Any) -> str: """ @classmethod - def validate_input_type(cls, value: Any, tp: Type): + def validate_input_type(cls, value: Any, tp: type): """Validate the input value type matches the required type.""" if not isinstance(value, tp): raise ConverterError( @@ -83,9 +79,9 @@ class ConverterFactory: __slots__ = "registry" def __init__(self): - self.registry: Dict[Type, Converter] = {} + self.registry: dict[type, Converter] = {} - def deserialize(self, value: Any, types: Sequence[Type], **kwargs: Any) -> Any: + def deserialize(self, value: Any, types: Sequence[type], **kwargs: Any) -> Any: """Attempt to convert any value to one of the given types. Args: @@ -132,7 +128,7 @@ def serialize(self, value: Any, **kwargs: Any) -> Any: def test( self, value: Optional[str], - types: Sequence[Type], + types: Sequence[type], strict: bool = False, **kwargs: Any, ) -> bool: @@ -166,7 +162,7 @@ def test( return True - def register_converter(self, data_type: Type, func: Union[Callable, Converter]): + def register_converter(self, data_type: type, func: Union[Callable, Converter]): """Register a callable or converter for the given data type. Args: @@ -178,7 +174,7 @@ def register_converter(self, data_type: Type, func: Union[Callable, Converter]): else: self.registry[data_type] = ProxyConverter(func) - def unregister_converter(self, data_type: Type): + def unregister_converter(self, data_type: type): """Unregister the converter for the given data type. Args: @@ -189,7 +185,7 @@ def unregister_converter(self, data_type: Type): """ self.registry.pop(data_type) - def type_converter(self, data_type: Type) -> Converter: + def type_converter(self, data_type: type) -> Converter: """Find a suitable converter for given data type. Iterate over all but last mro items and check for registered @@ -220,7 +216,7 @@ def value_converter(self, value: Any) -> Converter: return self.type_converter(value.__class__) @classmethod - def sort_types(cls, types: Sequence[Type]) -> List[Type]: + def sort_types(cls, types: Sequence[type]) -> list[type]: """Sort a list of types by giving priority to strict types first.""" if len(types) < 2: return list(types) @@ -228,7 +224,7 @@ def sort_types(cls, types: Sequence[Type]) -> List[Type]: return sorted(types, key=lambda x: __PYTHON_TYPES_SORTED__.get(x, 0)) @classmethod - def explicit_types(cls) -> Tuple[Type, ...]: + def explicit_types(cls) -> tuple[type, ...]: """Get a list of types that need strict test.""" return __EXPLICIT_TYPES__ @@ -503,7 +499,7 @@ class QNameConverter(Converter): def deserialize( self, value: str, - ns_map: Optional[Dict] = None, + ns_map: Optional[dict] = None, **kwargs: Any, ) -> QName: """Convert a string value to QName instance. @@ -534,7 +530,7 @@ def deserialize( def serialize( self, value: QName, - ns_map: Optional[Dict] = None, + ns_map: Optional[dict] = None, **kwargs: Any, ) -> str: """Convert a QName instance value sto string. @@ -568,7 +564,7 @@ def serialize( return f"{prefix}:{tag}" if prefix else tag @staticmethod - def resolve(value: str, ns_map: Optional[Dict] = None) -> Tuple[str, str]: + def resolve(value: str, ns_map: Optional[dict] = None) -> tuple[str, str]: """Split a qname or ns prefixed string value or a uri, name pair. Args: @@ -645,7 +641,7 @@ def deserialize( values = [value] length = len(values) - for member in cast(Type[Enum], data_type): + for member in cast(type[Enum], data_type): if self.match(value, values, length, member.value, **kwargs): return member diff --git a/xsdata/formats/dataclass/client.py b/xsdata/formats/dataclass/client.py index 98a90ff60..f484fadf2 100644 --- a/xsdata/formats/dataclass/client.py +++ b/xsdata/formats/dataclass/client.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, fields -from typing import Any, Dict, Optional, Type, Union +from typing import Any, Optional, Union from xsdata.exceptions import ClientValueError from xsdata.formats.dataclass.context import XmlContext @@ -25,8 +25,8 @@ class Config: location: str transport: str soap_action: str - input: Type - output: Type + input: type + output: type encoding: Optional[str] = None @classmethod @@ -97,7 +97,7 @@ def __init__( self.serializer = serializer @classmethod - def from_service(cls, obj: Type, **kwargs: Any) -> "Client": + def from_service(cls, obj: type, **kwargs: Any) -> "Client": """Instantiate client from a service class. Args: @@ -115,7 +115,7 @@ def from_service(cls, obj: Type, **kwargs: Any) -> "Client": """ return cls(config=Config.from_service(obj, **kwargs)) - def send(self, obj: Any, headers: Optional[Dict] = None) -> Any: + def send(self, obj: Any, headers: Optional[dict] = None) -> Any: """Build and send a request for the input object. ```py @@ -142,7 +142,7 @@ def send(self, obj: Any, headers: Optional[Dict] = None) -> Any: response = self.transport.post(self.config.location, data=data, headers=headers) return self.parser.from_bytes(response, self.config.output) - def prepare_headers(self, headers: Dict) -> Dict: + def prepare_headers(self, headers: dict) -> dict: """Prepare the request headers. It merges the custom user headers with the necessary headers @@ -178,7 +178,7 @@ def prepare_payload(self, obj: Any) -> Union[str, bytes]: Raises: ClientValueError: If the config input type doesn't match the given object. """ - if isinstance(obj, Dict): + if isinstance(obj, dict): decoder = DictDecoder(context=self.serializer.context) obj = decoder.decode(obj, self.config.input) diff --git a/xsdata/formats/dataclass/compat.py b/xsdata/formats/dataclass/compat.py index b51722b01..12aad3582 100644 --- a/xsdata/formats/dataclass/compat.py +++ b/xsdata/formats/dataclass/compat.py @@ -1,7 +1,8 @@ import abc +from collections.abc import Iterator from dataclasses import MISSING, fields, is_dataclass from types import MappingProxyType -from typing import Any, Dict, Iterator, Optional, Protocol, Set, Type +from typing import Any, Optional, Protocol from xsdata.exceptions import XmlContextError from xsdata.formats.dataclass.models.generics import AnyElement, DerivedElement @@ -25,21 +26,21 @@ class ClassType(abc.ABC): @property @abc.abstractmethod - def any_element(self) -> Type: + def any_element(self) -> Any: """Return the AnyElement used to bind wildcard element nodes.""" @property @abc.abstractmethod - def derived_element(self) -> Type: + def derived_element(self) -> Any: """Return the DerivedElement used to bind ambiguous element nodes.""" @property - def any_keys(self) -> Set[str]: + def any_keys(self) -> set[str]: """Return the field names of the AnyElement class.""" return {field.name for field in self.get_fields(self.any_element)} @property - def derived_keys(self) -> Set[str]: + def derived_keys(self) -> set[str]: """Return the field names of the DerivedElement class.""" return {field.name for field in self.get_fields(self.derived_element)} @@ -67,7 +68,7 @@ def default_value(self, field: FieldInfo, default: Optional[Any] = None) -> Any: """Return the default value or factory of the given model field.""" @abc.abstractmethod - def default_choice_value(self, choice: Dict) -> Any: + def default_choice_value(self, choice: dict) -> Any: """Return the default value or factory of the given model field choice.""" def score_object(self, obj: Any) -> float: @@ -114,7 +115,7 @@ class ClassTypes: __slots__ = "types" def __init__(self): - self.types: Dict[str, ClassType] = {} + self.types: dict[str, ClassType] = {} def register(self, name: str, fmt: ClassType, **_: Any): """Register a class type instance by name. @@ -147,12 +148,12 @@ class Dataclasses(ClassType): __slots__ = () @property - def any_element(self) -> Type: + def any_element(self) -> Any: """Return the generic any element class.""" return AnyElement @property - def derived_element(self) -> Type: + def derived_element(self) -> Any: """Return the generic derived element class.""" return DerivedElement @@ -186,7 +187,7 @@ def default_value(self, field: FieldInfo, default: Optional[Any] = None) -> Any: return default - def default_choice_value(self, choice: Dict) -> Any: + def default_choice_value(self, choice: dict) -> Any: """Return the default value or factory of the given model field choice.""" factory = choice.get("default_factory") if callable(factory): diff --git a/xsdata/formats/dataclass/context.py b/xsdata/formats/dataclass/context.py index 466448e2a..73a5372f5 100644 --- a/xsdata/formats/dataclass/context.py +++ b/xsdata/formats/dataclass/context.py @@ -1,7 +1,8 @@ import sys from collections import defaultdict +from collections.abc import Iterator from contextlib import suppress -from typing import Any, Callable, Dict, Iterator, List, Optional, Set, Type +from typing import Any, Callable, Optional from xsdata.exceptions import XmlContextError from xsdata.formats.dataclass.compat import class_types @@ -51,8 +52,8 @@ def __init__( self.attribute_name_generator = attribute_name_generator self.class_type = class_types.get_type(class_type) - self.cache: Dict[Type, XmlMeta] = {} - self.xsi_cache: Dict[str, List[Type]] = defaultdict(list) + self.cache: dict[type, XmlMeta] = {} + self.xsi_cache: dict[str, list[type]] = defaultdict(list) self.models_package = models_package self.sys_modules = 0 @@ -64,7 +65,7 @@ def reset(self): def get_builder( self, - globalns: Optional[Dict[str, Callable]] = None, + globalns: Optional[dict[str, Callable]] = None, ) -> XmlMetaBuilder: """Return a new xml meta builder instance.""" return XmlMetaBuilder( @@ -76,7 +77,7 @@ def get_builder( def fetch( self, - clazz: Type, + clazz: type, parent_ns: Optional[str] = None, xsi_type: Optional[str] = None, ) -> XmlMeta: @@ -115,7 +116,7 @@ def build_xsi_cache(self): self.sys_modules = len(sys.modules) - def is_binding_model(self, clazz: Type[T]) -> bool: + def is_binding_model(self, clazz: type[T]) -> bool: """Return whether the clazz is a binding model. If the models package is not empty also validate @@ -136,7 +137,7 @@ def is_binding_model(self, clazz: Type[T]) -> bool: and clazz.__module__.startswith(self.models_package) ) - def find_types(self, qname: str) -> List[Type[T]]: + def find_types(self, qname: str) -> list[type[T]]: """Find all classes that match the given xsi:type qname. - Ignores native schema types, xs:string, xs:float, xs:int, ... @@ -155,7 +156,7 @@ def find_types(self, qname: str) -> List[Type[T]]: return [] - def find_type(self, qname: str) -> Optional[Type[T]]: + def find_type(self, qname: str) -> Optional[type[T]]: """Return the last imported class that matches the given xsi:type qname. Args: @@ -164,10 +165,10 @@ def find_type(self, qname: str) -> Optional[Type[T]]: Returns: A class type or None if no matches. """ - types: List[Type] = self.find_types(qname) + types: list[type] = self.find_types(qname) return types[-1] if types else None - def find_type_by_fields(self, field_names: Set[str]) -> Optional[Type[T]]: + def find_type_by_fields(self, field_names: set[str]) -> Optional[type[T]]: """Find a data class that matches best the given list of field names. Args: @@ -179,7 +180,7 @@ def find_type_by_fields(self, field_names: Set[str]) -> Optional[Type[T]]: fields, return the one with the least extra fields. """ - def get_field_diff(clazz: Type) -> int: + def get_field_diff(clazz: type) -> int: meta = self.cache[clazz] local_names = {var.local_name for var in meta.get_all_vars()} return len(local_names - field_names) @@ -195,7 +196,7 @@ def get_field_diff(clazz: Type) -> int: choices.sort(key=lambda x: (x[1], x[0].__name__)) return choices[0][0] if choices else None - def find_subclass(self, clazz: Type, qname: str) -> Optional[Type]: + def find_subclass(self, clazz: type, qname: str) -> Optional[type]: """Find a subclass for the given clazz and xsi:type qname. Compare all classes that match the given xsi:type qname and return the @@ -209,7 +210,7 @@ def find_subclass(self, clazz: Type, qname: str) -> Optional[Type]: Returns: The matching class type or None if no matches. """ - types: List[Type] = self.find_types(qname) + types: list[type] = self.find_types(qname) for tp in types: # Why would a xml node with have a xsi:type that points # to parent class is beyond me, but it happens, let's protect @@ -225,9 +226,9 @@ def find_subclass(self, clazz: Type, qname: str) -> Optional[Type]: def build( self, - clazz: Type, + clazz: type, parent_ns: Optional[str] = None, - globalns: Optional[Dict[str, Callable]] = None, + globalns: Optional[dict[str, Callable]] = None, ) -> XmlMeta: """Fetch or build the binding metadata for the given class. @@ -244,7 +245,7 @@ def build( self.cache[clazz] = builder.build(clazz, parent_ns) return self.cache[clazz] - def build_recursive(self, clazz: Type, parent_ns: Optional[str] = None): + def build_recursive(self, clazz: type, parent_ns: Optional[str] = None): """Build the binding metadata for the given class and all of its dependencies. This method is used in benchmarks! @@ -261,7 +262,7 @@ def build_recursive(self, clazz: Type, parent_ns: Optional[str] = None): if self.class_type.is_model(tp): self.build_recursive(tp, meta.namespace) - def local_names_match(self, names: Set[str], clazz: Type) -> bool: + def local_names_match(self, names: set[str], clazz: type) -> bool: """Check if the given field names match the given class type. Silently ignore, typing errors. These classes are from third @@ -289,7 +290,7 @@ def local_names_match(self, names: Set[str], clazz: Type) -> bool: return False @classmethod - def is_derived(cls, obj: Any, clazz: Type) -> bool: + def is_derived(cls, obj: Any, clazz: type) -> bool: """Return whether the obj is a subclass or a parent of the given class type.""" if obj is None: return False @@ -300,7 +301,7 @@ def is_derived(cls, obj: Any, clazz: Type) -> bool: return any(x is not object and isinstance(obj, x) for x in clazz.__bases__) @classmethod - def get_subclasses(cls, clazz: Type) -> Iterator[Type]: + def get_subclasses(cls, clazz: type) -> Iterator[type]: """Return an iterator of the given class subclasses.""" with suppress(TypeError): for subclass in clazz.__subclasses__(): diff --git a/xsdata/formats/dataclass/generator.py b/xsdata/formats/dataclass/generator.py index 1c1558364..285c1055c 100644 --- a/xsdata/formats/dataclass/generator.py +++ b/xsdata/formats/dataclass/generator.py @@ -1,10 +1,10 @@ import importlib import pkgutil -import re import subprocess import sys +from collections.abc import Iterator from pathlib import Path -from typing import Iterator, List, Optional +from typing import Optional from jinja2 import Environment, FileSystemLoader @@ -46,11 +46,11 @@ def __init__(self, config: GeneratorConfig): self.ruff_config = Path(__file__).parent / "ruff.toml" @classmethod - def get_template_paths(cls) -> List[str]: + def get_template_paths(cls) -> list[str]: """Return a list of template paths to feed the jinja2 loader.""" return [str(Path(__file__).parent.joinpath("templates"))] - def render(self, classes: List[Class]) -> Iterator[GeneratorResult]: + def render(self, classes: list[Class]) -> Iterator[GeneratorResult]: """Render the given classes to python packages and modules. Args: @@ -111,7 +111,7 @@ def import_package(package_name): package = self.config.output.package import_package(self.package_name(package)) - def render_package(self, classes: List[Class], module: str) -> str: + def render_package(self, classes: list[Class], module: str) -> str: """Render the package for the given classes. Args: @@ -135,7 +135,7 @@ def render_package(self, classes: List[Class], module: str) -> str: def render_module( self, resolver: DependenciesResolver, - classes: List[Class], + classes: list[Class], ) -> str: """Render the module for the given classes. @@ -167,7 +167,7 @@ def render_module( def render_classes( self, - classes: List[Class], + classes: list[Class], module_namespace: Optional[str], ) -> str: """Render the classes source code in a module. @@ -232,7 +232,7 @@ def init_filters(cls, config: GeneratorConfig) -> Filters: """Initialize the filters instance by the generator configuration.""" return Filters(config) - def ruff_code(self, file_paths: List[str]): + def ruff_code(self, file_paths: list[str]): """Run ruff lint and format on a list of file names. Args: diff --git a/xsdata/formats/dataclass/models/builders.py b/xsdata/formats/dataclass/models/builders.py index 62d9cd9fa..b934411a5 100644 --- a/xsdata/formats/dataclass/models/builders.py +++ b/xsdata/formats/dataclass/models/builders.py @@ -1,18 +1,11 @@ import sys from collections import defaultdict +from collections.abc import Iterator, Mapping, Sequence from enum import Enum from typing import ( Any, Callable, - Dict, - Iterator, - List, - Mapping, Optional, - Sequence, - Set, - Tuple, - Type, get_type_hints, ) @@ -34,7 +27,7 @@ from xsdata.utils.constants import EMPTY_SEQUENCE, return_input from xsdata.utils.namespaces import build_qname -evaluations: Dict[str, Callable] = { +evaluations: dict[str, Callable] = { XmlType.TEXT: evaluate_text, XmlType.ELEMENT: evaluate_element, XmlType.ELEMENTS: evaluate_elements, @@ -108,14 +101,14 @@ def __init__( class_type: ClassType, element_name_generator: Callable, attribute_name_generator: Callable, - globalns: Optional[Dict[str, Callable]] = None, + globalns: Optional[dict[str, Callable]] = None, ): self.class_type = class_type self.element_name_generator = element_name_generator self.attribute_name_generator = attribute_name_generator self.globalns = globalns - def build(self, clazz: Type, parent_namespace: Optional[str]) -> XmlMeta: + def build(self, clazz: type, parent_namespace: Optional[str]) -> XmlMeta: """Build the binding metadata for a dataclass and its fields. Args: @@ -136,8 +129,8 @@ def build(self, clazz: Type, parent_namespace: Optional[str]) -> XmlMeta: ) attributes = {} - elements: Dict[str, List[XmlVar]] = defaultdict(list) - wrappers: Dict[str, str] = {} + elements: dict[str, list[XmlVar]] = defaultdict(list) + wrappers: dict[str, str] = {} choices = [] any_attributes = [] wildcards = [] @@ -175,7 +168,7 @@ def build(self, clazz: Type, parent_namespace: Optional[str]) -> XmlMeta: def build_vars( self, - clazz: Type, + clazz: type, namespace: Optional[str], element_name_generator: Callable, attribute_name_generator: Callable, @@ -221,7 +214,7 @@ def build_vars( def build_class_meta( self, - clazz: Type, + clazz: Any, parent_namespace: Optional[str] = None, ) -> ClassMeta: """Build the class meta options and merge with the defaults. @@ -267,7 +260,7 @@ def build_class_meta( ) @classmethod - def find_declared_class(cls, clazz: Type, name: str) -> Type: + def find_declared_class(cls, clazz: type, name: str) -> Any: """Find the user class that matches the name. Todo: Honestly I have no idea why we needed this. @@ -280,7 +273,7 @@ def find_declared_class(cls, clazz: Type, name: str) -> Type: raise XmlContextError(f"Failed to detect the declared class for field {name}") @classmethod - def is_inner_class(cls, clazz: Type) -> bool: + def is_inner_class(cls, clazz: type) -> bool: """Return whether the given type is nested inside another type.""" return "." in clazz.__qualname__ @@ -297,7 +290,7 @@ def target_namespace(cls, module: Any, meta: Any) -> Optional[str]: return getattr(meta, "namespace", None) - def default_xml_type(self, clazz: Type) -> str: + def default_xml_type(self, clazz: type) -> str: """Return the default xml type for the fields of the given dataclass. If a class has fields with no xml type defined, attempt @@ -306,7 +299,7 @@ def default_xml_type(self, clazz: Type) -> str: # Todo hacks like this are so unnecessary... """ - counters: Dict[str, int] = defaultdict(int) + counters: dict[str, int] = defaultdict(int) for var in self.class_type.get_fields(clazz): xml_type = var.metadata.get("type") counters[xml_type or "undefined"] += 1 @@ -358,7 +351,7 @@ def __init__( def build( self, - model: Type, + model: type, name: str, type_hint: Any, metadata: Mapping[str, Any], @@ -459,9 +452,9 @@ def build( def build_choices( self, - model: Type, + model: type, name: str, - choices: List[Dict], + choices: list[dict], factory: Optional[Callable], globalns: Any, parent_namespace: Optional[str], @@ -479,7 +472,7 @@ def build_choices( Yields: An iterator of field choice binding metadata instance. """ - existing_types: Set[type] = set() + existing_types: set[type] = set() for choice in choices: default_value = self.class_type.default_choice_value(choice) @@ -539,7 +532,7 @@ def resolve_namespaces( xml_type: Optional[str], namespace: Optional[str], parent_namespace: Optional[str], - ) -> Tuple[str, ...]: + ) -> tuple[str, ...]: """Resolve a fields supported namespaces. Only elements and wildcards are allowed to inherit the parent @@ -576,14 +569,14 @@ def resolve_namespaces( return tuple(result) @classmethod - def is_any_type(cls, types: Sequence[Type], xml_type: str) -> bool: + def is_any_type(cls, types: Sequence[type], xml_type: str) -> bool: """Return whether the given xml type supports generic values.""" if xml_type in (XmlType.ELEMENT, XmlType.ELEMENTS): return object in types return False - def is_typing_supported(self, types: Sequence[Type]) -> bool: + def is_typing_supported(self, types: Sequence[type]) -> bool: """Validate all types are registered in the converter.""" for tp in types: if ( diff --git a/xsdata/formats/dataclass/models/elements.py b/xsdata/formats/dataclass/models/elements.py index 01faf2d3f..a6fde4bb2 100644 --- a/xsdata/formats/dataclass/models/elements.py +++ b/xsdata/formats/dataclass/models/elements.py @@ -1,18 +1,11 @@ import itertools import operator import sys +from collections.abc import Iterator, Mapping, Sequence from typing import ( Any, Callable, - Dict, - Iterator, - List, - Mapping, Optional, - Sequence, - Set, - Tuple, - Type, ) from xsdata.formats.converter import converter @@ -38,7 +31,7 @@ class XmlType: class MetaMixin: """Use this mixin for unit tests only!!!""" - __slots__: Tuple[str, ...] = () + __slots__: tuple[str, ...] = () def __eq__(self, other: Any) -> bool: """Implement equality operator.""" @@ -156,8 +149,8 @@ def __init__( name: str, local_name: str, wrapper: Optional[str], - types: Sequence[Type], - clazz: Optional[Type], + types: Sequence[type], + clazz: Optional[type], init: bool, mixed: bool, factory: Optional[Callable], @@ -199,7 +192,7 @@ def __init__( self.factory = factory self.tokens_factory = tokens_factory - self.namespace_matches: Optional[Dict[str, bool]] = None + self.namespace_matches: Optional[dict[str, bool]] = None self.is_clazz_union = self.clazz and len(types) > 1 namespace = default_namespace(namespaces) @@ -230,7 +223,7 @@ def __init__( self.is_text = True @property - def element_types(self) -> Set[Type]: + def element_types(self) -> set[type]: """Return the unique element types.""" return {tp for element in self.elements.values() for tp in element.types} @@ -285,7 +278,7 @@ def find_nillable_choice(self, is_tokens: bool) -> Optional["XmlVar"]: if element.nillable and is_tokens == element.tokens ) - def find_clazz_choice(self, clazz: Type) -> Optional["XmlVar"]: + def find_clazz_choice(self, clazz: type) -> Optional["XmlVar"]: """Find the best matching choice for the given class. Best Matches: @@ -431,7 +424,7 @@ class XmlMeta(MetaMixin): def __init__( self, - clazz: Type, + clazz: type, qname: str, target_qname: Optional[str], nillable: bool, @@ -459,7 +452,7 @@ def __init__( self.wrappers = wrappers @property - def element_types(self) -> Set[Type]: + def element_types(self) -> set[type]: """Return a unique list of all elements types.""" return { tp @@ -468,7 +461,7 @@ def element_types(self) -> Set[Type]: for tp in element.types } - def get_element_vars(self) -> List[XmlVar]: + def get_element_vars(self) -> list[XmlVar]: """Return a sorted list of the class element variables.""" result = list( itertools.chain(self.wildcards, self.choices, *self.elements.values()) @@ -478,12 +471,12 @@ def get_element_vars(self) -> List[XmlVar]: return sorted(result, key=get_index) - def get_attribute_vars(self) -> List[XmlVar]: + def get_attribute_vars(self) -> list[XmlVar]: """Return a sorted list of the class attribute variables.""" result = itertools.chain(self.any_attributes, self.attributes.values()) return sorted(result, key=get_index) - def get_all_vars(self) -> List[XmlVar]: + def get_all_vars(self) -> list[XmlVar]: """Return a sorted list of all the class variables.""" result = list( itertools.chain( diff --git a/xsdata/formats/dataclass/models/generics.py b/xsdata/formats/dataclass/models/generics.py index af1f7b4f3..5c2ddc330 100644 --- a/xsdata/formats/dataclass/models/generics.py +++ b/xsdata/formats/dataclass/models/generics.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Dict, Generic, List, Optional, TypeVar +from typing import Generic, Optional, TypeVar from xsdata.formats.dataclass.models.elements import XmlType @@ -21,10 +21,10 @@ class AnyElement: qname: Optional[str] = field(default=None) text: Optional[str] = field(default=None) tail: Optional[str] = field(default=None) - children: List[object] = field( + children: list[object] = field( default_factory=list, metadata={"type": XmlType.WILDCARD} ) - attributes: Dict[str, str] = field( + attributes: dict[str, str] = field( default_factory=dict, metadata={"type": XmlType.ATTRIBUTES} ) diff --git a/xsdata/formats/dataclass/parsers/bases.py b/xsdata/formats/dataclass/parsers/bases.py index d0a3f4347..16fec4c12 100644 --- a/xsdata/formats/dataclass/parsers/bases.py +++ b/xsdata/formats/dataclass/parsers/bases.py @@ -1,9 +1,8 @@ import copy -import warnings from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple, Type, cast +from typing import Any, Optional, cast -from xsdata.exceptions import ConverterWarning, ParserError +from xsdata.exceptions import ParserError from xsdata.formats.dataclass.context import XmlContext from xsdata.formats.dataclass.parsers.mixins import ( EventsHandler, @@ -15,7 +14,7 @@ from xsdata.formats.types import T from xsdata.models.enums import EventType -Parsed = Tuple[Optional[str], Any] +Parsed = tuple[Optional[str], Any] @dataclass @@ -31,13 +30,13 @@ class NodeParser(PushParser): """ context: XmlContext = field(default_factory=XmlContext) - handler: Type[XmlHandler] = field(default=EventsHandler) + handler: type[XmlHandler] = field(default=EventsHandler) def parse( self, source: Any, - clazz: Optional[Type[T]] = None, - ns_map: Optional[Dict[Optional[str], str]] = None, + clazz: Optional[type[T]] = None, + ns_map: Optional[dict[Optional[str], str]] = None, ) -> T: """Parse the input file or stream into the target class type. @@ -68,12 +67,12 @@ def parse( def start( self, - clazz: Optional[Type], - queue: List[XmlNode], - objects: List[Parsed], + clazz: Optional[type], + queue: list[XmlNode], + objects: list[Parsed], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, ): """Build and queue the XmlNode for the starting element. @@ -131,8 +130,8 @@ def start( def end( self, - queue: List[XmlNode], - objects: List[Parsed], + queue: list[XmlNode], + objects: list[Parsed], qname: str, text: Optional[str], tail: Optional[str], @@ -154,12 +153,12 @@ def end( def find_root_clazz( self, - clazz: Optional[Type], + clazz: Optional[type], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, xsi_type: Optional[str], - ) -> Optional[Type]: + ) -> Optional[type]: """ Obtain the root clazz, maybe from the provided clazz. @@ -191,16 +190,16 @@ class RecordParser(NodeParser): events: The list of recorded events """ - events: List = field(init=False, default_factory=list) + events: list = field(init=False, default_factory=list) def start( self, - clazz: Optional[Type], - queue: List[XmlNode], - objects: List[Parsed], + clazz: Optional[type], + queue: list[XmlNode], + objects: list[Parsed], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, ): """Build and queue the XmlNode for the starting element. @@ -219,8 +218,8 @@ def start( def end( self, - queue: List[XmlNode], - objects: List[Parsed], + queue: list[XmlNode], + objects: list[Parsed], qname: str, text: Optional[str], tail: Optional[str], @@ -243,7 +242,7 @@ def end( return super().end(queue, objects, qname, text, tail) def register_namespace( - self, ns_map: Dict[Optional[str], str], prefix: Optional[str], uri: str + self, ns_map: dict[Optional[str], str], prefix: Optional[str], uri: str ): """Register the uri prefix in the namespace prefix-URI map. diff --git a/xsdata/formats/dataclass/parsers/config.py b/xsdata/formats/dataclass/parsers/config.py index bed205179..c339090e4 100644 --- a/xsdata/formats/dataclass/parsers/config.py +++ b/xsdata/formats/dataclass/parsers/config.py @@ -1,10 +1,10 @@ from dataclasses import dataclass, field -from typing import Any, Callable, Dict, Optional, Type +from typing import Any, Callable, Optional from xsdata.formats.types import T -def default_class_factory(cls: Type[T], params: Dict[str, Any]) -> T: +def default_class_factory(cls: type[T], params: dict[str, Any]) -> T: """The default class factory. To be used as a hook for plugins. @@ -39,7 +39,7 @@ class ParserConfig: base_url: Optional[str] = None load_dtd: bool = False process_xinclude: bool = False - class_factory: Callable[[Type[T], Dict[str, Any]], T] = field( + class_factory: Callable[[type[T], dict[str, Any]], T] = field( default=default_class_factory ) fail_on_unknown_properties: bool = True diff --git a/xsdata/formats/dataclass/parsers/dict.py b/xsdata/formats/dataclass/parsers/dict.py index 5b167fd3f..f031de542 100644 --- a/xsdata/formats/dataclass/parsers/dict.py +++ b/xsdata/formats/dataclass/parsers/dict.py @@ -1,6 +1,7 @@ +from collections.abc import Iterable from contextlib import suppress from dataclasses import dataclass, field, replace -from typing import Any, Dict, Iterable, List, Optional, Type, Union +from typing import Any, Optional, Union from typing_extensions import get_args, get_origin @@ -27,7 +28,7 @@ class DictDecoder: config: ParserConfig = field(default_factory=ParserConfig) context: XmlContext = field(default_factory=XmlContext) - def decode(self, data: Union[List, Dict], clazz: Optional[Type[T]] = None) -> T: + def decode(self, data: Union[list, dict], clazz: Optional[type[T]] = None) -> T: """Parse the input stream into the target class type. If no clazz is provided, the binding context will try @@ -46,7 +47,7 @@ def decode(self, data: Union[List, Dict], clazz: Optional[Type[T]] = None) -> T: return [self.bind_dataclass(obj, tp) for obj in data] # type: ignore - def verify_type(self, clazz: Optional[Type[T]], data: Union[Dict, List]) -> Type[T]: + def verify_type(self, clazz: Optional[type[T]], data: Union[dict, list]) -> type[T]: """Verify the given data matches the given clazz. If no clazz is provided, the binding context will try @@ -85,7 +86,7 @@ def verify_type(self, clazz: Optional[Type[T]], data: Union[Dict, List]) -> Type return clazz # type: ignore - def detect_type(self, data: Union[Dict, List]) -> Type[T]: + def detect_type(self, data: Union[dict, list]) -> type[T]: """Locate the target clazz type from the data keys. Args: @@ -98,14 +99,14 @@ def detect_type(self, data: Union[Dict, List]) -> Type[T]: raise ParserError("Document is empty, can not detect type") keys = data[0].keys() if isinstance(data, list) else data.keys() - clazz: Optional[Type[T]] = self.context.find_type_by_fields(set(keys)) + clazz: Optional[type[T]] = self.context.find_type_by_fields(set(keys)) if clazz: return clazz raise ParserError(f"Unable to locate model with properties({list(keys)})") - def bind_dataclass(self, data: Dict, clazz: Type[T]) -> T: + def bind_dataclass(self, data: dict, clazz: type[T]) -> T: """Create a new instance of the given class type with the given data. Args: @@ -145,7 +146,7 @@ def bind_dataclass(self, data: Dict, clazz: Type[T]) -> T: except TypeError as e: raise ParserError(e) - def bind_derived_dataclass(self, data: Dict, clazz: Type[T]) -> Any: + def bind_derived_dataclass(self, data: dict, clazz: type[T]) -> Any: """Bind the input data to the given class type. Examples: @@ -169,7 +170,7 @@ def bind_derived_dataclass(self, data: Dict, clazz: Type[T]) -> Any: generic = self.context.class_type.derived_element if clazz is generic: - real_clazz: Optional[Type[T]] = None + real_clazz: Optional[type[T]] = None if xsi_type: real_clazz = self.context.find_type(xsi_type) @@ -185,7 +186,7 @@ def bind_derived_dataclass(self, data: Dict, clazz: Type[T]) -> Any: return generic(qname=qname, type=xsi_type, value=value) - def bind_best_dataclass(self, data: Dict, classes: Iterable[Type[T]]) -> T: + def bind_best_dataclass(self, data: dict, classes: Iterable[type[T]]) -> T: """Bind the input data to all the given classes and return best match. Args: @@ -309,7 +310,7 @@ def bind_text(self, meta: XmlMeta, var: XmlVar, value: Any) -> Any: ns_map=EMPTY_MAP, ) - def bind_complex_type(self, meta: XmlMeta, var: XmlVar, data: Dict) -> Any: + def bind_complex_type(self, meta: XmlMeta, var: XmlVar, data: dict) -> Any: """Bind complex values entrypoint. Args: @@ -340,7 +341,7 @@ def bind_complex_type(self, meta: XmlMeta, var: XmlVar, data: Dict) -> Any: return self.bind_dataclass(data, var.clazz) - def bind_derived_value(self, meta: XmlMeta, var: XmlVar, data: Dict) -> Any: + def bind_derived_value(self, meta: XmlMeta, var: XmlVar, data: dict) -> Any: """Bind derived data entrypoint. The data is representation of a derived element, e.g. { @@ -376,7 +377,7 @@ def bind_derived_value(self, meta: XmlMeta, var: XmlVar, data: Dict) -> Any: # Is this scenario still possible??? value = self.bind_text(meta, var, params) elif xsi_type: - clazz: Optional[Type] = self.context.find_type(xsi_type) + clazz: Optional[type] = self.context.find_type(xsi_type) if clazz is None: raise ParserError(f"Unable to locate xsi:type `{xsi_type}`") @@ -393,7 +394,7 @@ def bind_derived_value(self, meta: XmlMeta, var: XmlVar, data: Dict) -> Any: @classmethod def find_var( cls, - xml_vars: List[XmlVar], + xml_vars: list[XmlVar], key: str, value: Any, ) -> Optional[XmlVar]: diff --git a/xsdata/formats/dataclass/parsers/handlers/__init__.py b/xsdata/formats/dataclass/parsers/handlers/__init__.py index cf1bc05af..d718b93a2 100644 --- a/xsdata/formats/dataclass/parsers/handlers/__init__.py +++ b/xsdata/formats/dataclass/parsers/handlers/__init__.py @@ -1,18 +1,16 @@ -from typing import Type - from xsdata.formats.dataclass.parsers.handlers.native import XmlEventHandler from xsdata.formats.dataclass.parsers.mixins import XmlHandler try: from xsdata.formats.dataclass.parsers.handlers.lxml import LxmlEventHandler - def default_handler() -> Type[XmlHandler]: + def default_handler() -> type[XmlHandler]: """Return the default xml handler.""" return LxmlEventHandler except ImportError: # pragma: no cover - def default_handler() -> Type[XmlHandler]: + def default_handler() -> type[XmlHandler]: """Return the default xml handler.""" return XmlEventHandler diff --git a/xsdata/formats/dataclass/parsers/handlers/lxml.py b/xsdata/formats/dataclass/parsers/handlers/lxml.py index b5fd8fc3a..441877808 100644 --- a/xsdata/formats/dataclass/parsers/handlers/lxml.py +++ b/xsdata/formats/dataclass/parsers/handlers/lxml.py @@ -1,4 +1,5 @@ -from typing import Any, Dict, Iterable, Optional, Tuple +from collections.abc import Iterable +from typing import Any, Optional from lxml import etree @@ -12,7 +13,7 @@ class LxmlEventHandler(XmlHandler): """An lxml event handler.""" - def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: + def parse(self, source: Any, ns_map: dict[Optional[str], str]) -> Any: """Parse the source XML document. Args: @@ -42,8 +43,8 @@ def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: def process_context( self, - context: Iterable[Tuple[str, Any]], - ns_map: Dict[Optional[str], str], + context: Iterable[tuple[str, Any]], + ns_map: dict[Optional[str], str], ) -> Any: """Iterate context and push events to main parser. diff --git a/xsdata/formats/dataclass/parsers/handlers/native.py b/xsdata/formats/dataclass/parsers/handlers/native.py index f149d7959..d935de67d 100644 --- a/xsdata/formats/dataclass/parsers/handlers/native.py +++ b/xsdata/formats/dataclass/parsers/handlers/native.py @@ -1,5 +1,6 @@ import functools -from typing import Any, Dict, Iterable, Iterator, Optional, Tuple +from collections.abc import Iterable, Iterator +from typing import Any, Optional from urllib.parse import urljoin from xml.etree import ElementInclude as xinclude from xml.etree import ElementTree as etree @@ -15,7 +16,7 @@ class XmlEventHandler(XmlHandler): """A native xml event handler.""" - def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: + def parse(self, source: Any, ns_map: dict[Optional[str], str]) -> Any: """Parse the source XML document. Args: @@ -44,7 +45,7 @@ def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: return self.process_context(ctx, ns_map) def process_context( - self, context: Iterable[Tuple[str, Any]], ns_map: Dict[Optional[str], str] + self, context: Iterable[tuple[str, Any]], ns_map: dict[Optional[str], str] ) -> Any: """Iterate context and push events to main parser. @@ -55,7 +56,7 @@ def process_context( Returns: An instance of the class type representing the parsed content. """ - element_ns_map: Dict = {} + element_ns_map: dict = {} for event, element in context: if event == EventType.START: self.parser.start( @@ -87,7 +88,7 @@ def process_context( return self.objects[-1][1] if self.objects else None - def merge_parent_namespaces(self, ns_map: Dict[Optional[str], str]) -> Dict: + def merge_parent_namespaces(self, ns_map: dict[Optional[str], str]) -> dict: """Merge the given prefix-URI map with the parent node map. This method also registers new prefixes with the parser. @@ -114,7 +115,7 @@ def merge_parent_namespaces(self, ns_map: Dict[Optional[str], str]) -> Dict: return result -def iterwalk(element: etree.Element, ns_map: Dict) -> Iterator[Tuple[str, Any]]: +def iterwalk(element: etree.Element, ns_map: dict) -> Iterator[tuple[str, Any]]: """Walk over the element tree and emit events. The ElementTree doesn't preserve the original namespace prefixes, we diff --git a/xsdata/formats/dataclass/parsers/json.py b/xsdata/formats/dataclass/parsers/json.py index 0b95b0b13..a350ccb28 100644 --- a/xsdata/formats/dataclass/parsers/json.py +++ b/xsdata/formats/dataclass/parsers/json.py @@ -2,7 +2,7 @@ import json import pathlib from dataclasses import dataclass, field -from typing import Any, Callable, Dict, List, Optional, Type, Union +from typing import Any, Callable, Optional, Union from xsdata.formats.dataclass.parsers import DictDecoder from xsdata.formats.types import T @@ -20,7 +20,7 @@ class JsonParser(DictDecoder): load_factory: Callable = field(default=json.load) - def from_path(self, path: pathlib.Path, clazz: Optional[Type[T]] = None) -> T: + def from_path(self, path: pathlib.Path, clazz: Optional[type[T]] = None) -> T: """Parse the input file into the target class type. If no clazz is provided, the binding context will try @@ -35,7 +35,7 @@ def from_path(self, path: pathlib.Path, clazz: Optional[Type[T]] = None) -> T: """ return self.parse(str(path.resolve()), clazz) - def from_string(self, source: str, clazz: Optional[Type[T]] = None) -> T: + def from_string(self, source: str, clazz: Optional[type[T]] = None) -> T: """Parse the input source string into the target class type. If no clazz is provided, the binding context will try @@ -50,7 +50,7 @@ def from_string(self, source: str, clazz: Optional[Type[T]] = None) -> T: """ return self.from_bytes(source.encode(), clazz) - def from_bytes(self, source: bytes, clazz: Optional[Type[T]] = None) -> T: + def from_bytes(self, source: bytes, clazz: Optional[type[T]] = None) -> T: """Parse the input source bytes object into the target class type. If no clazz is provided, the binding context will try @@ -65,7 +65,7 @@ def from_bytes(self, source: bytes, clazz: Optional[Type[T]] = None) -> T: """ return self.parse(io.BytesIO(source), clazz) - def parse(self, source: Any, clazz: Optional[Type[T]] = None) -> T: + def parse(self, source: Any, clazz: Optional[type[T]] = None) -> T: """Parse the input stream into the target class type. If no clazz is provided, the binding context will try @@ -81,7 +81,7 @@ def parse(self, source: Any, clazz: Optional[Type[T]] = None) -> T: data = self.load_json(source) return self.decode(data, clazz) - def load_json(self, source: Any) -> Union[Dict, List]: + def load_json(self, source: Any) -> Union[dict, list]: """Load the given json source filename or stream. Args: diff --git a/xsdata/formats/dataclass/parsers/mixins.py b/xsdata/formats/dataclass/parsers/mixins.py index 3c7399578..fdd3853fe 100644 --- a/xsdata/formats/dataclass/parsers/mixins.py +++ b/xsdata/formats/dataclass/parsers/mixins.py @@ -2,7 +2,7 @@ import io import pathlib from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Tuple, Type +from typing import Any, Optional from xsdata.exceptions import XmlHandlerError from xsdata.formats.dataclass.parsers.config import ParserConfig @@ -22,13 +22,13 @@ class PushParser: """ config: ParserConfig = field(default_factory=ParserConfig) - ns_map: Dict[Optional[str], str] = field(init=False, default_factory=dict) + ns_map: dict[Optional[str], str] = field(init=False, default_factory=dict) def from_path( self, path: pathlib.Path, - clazz: Optional[Type[T]] = None, - ns_map: Optional[Dict[Optional[str], str]] = None, + clazz: Optional[type[T]] = None, + ns_map: Optional[dict[Optional[str], str]] = None, ) -> T: """Parse the input file into the target class type. @@ -48,8 +48,8 @@ def from_path( def from_string( self, source: str, - clazz: Optional[Type[T]] = None, - ns_map: Optional[Dict[Optional[str], str]] = None, + clazz: Optional[type[T]] = None, + ns_map: Optional[dict[Optional[str], str]] = None, ) -> T: """Parse the input source string into the target class type. @@ -69,8 +69,8 @@ def from_string( def from_bytes( self, source: bytes, - clazz: Optional[Type[T]] = None, - ns_map: Optional[Dict[Optional[str], str]] = None, + clazz: Optional[type[T]] = None, + ns_map: Optional[dict[Optional[str], str]] = None, ) -> T: """Parse the input source bytes object into the target class type. @@ -91,8 +91,8 @@ def from_bytes( def parse( self, source: Any, - clazz: Optional[Type[T]] = None, - ns_map: Optional[Dict[Optional[str], str]] = None, + clazz: Optional[type[T]] = None, + ns_map: Optional[dict[Optional[str], str]] = None, ) -> T: """Parse the input file or stream into the target class type. @@ -111,12 +111,12 @@ def parse( @abc.abstractmethod def start( self, - clazz: Optional[Type], - queue: List[Any], - objects: List[Any], + clazz: Optional[type], + queue: list[Any], + objects: list[Any], qname: str, - attrs: Dict[str, str], - ns_map: Dict[Optional[str], str], + attrs: dict[str, str], + ns_map: dict[Optional[str], str], ): """Build and queue the XmlNode for the starting element. @@ -132,8 +132,8 @@ def start( @abc.abstractmethod def end( self, - queue: List, - objects: List, + queue: list, + objects: list, qname: str, text: Optional[str], tail: Optional[str], @@ -152,7 +152,7 @@ def end( """ def register_namespace( - self, ns_map: Dict[Optional[str], str], prefix: Optional[str], uri: str + self, ns_map: dict[Optional[str], str], prefix: Optional[str], uri: str ): """Register the uri prefix in the namespace prefix-URI map. @@ -177,7 +177,7 @@ class XmlNode(abc.ABC): __slots__ = () @abc.abstractmethod - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> "XmlNode": + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> "XmlNode": """Initialize the next child node to be queued, when an element starts. This entry point is responsible to create the next node type @@ -200,7 +200,7 @@ def bind( qname: str, text: Optional[str], tail: Optional[str], - objects: List[Any], + objects: list[Any], ) -> bool: """Bind the parsed data into an object for the ending element. @@ -233,13 +233,13 @@ class XmlHandler: __slots__ = ("parser", "clazz", "queue", "objects") - def __init__(self, parser: PushParser, clazz: Optional[Type]): + def __init__(self, parser: PushParser, clazz: Optional[type]): self.parser = parser self.clazz = clazz - self.queue: List = [] - self.objects: List = [] + self.queue: list = [] + self.objects: list = [] - def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: + def parse(self, source: Any, ns_map: dict[Optional[str], str]) -> Any: """Parse the source XML document. Args: @@ -255,7 +255,7 @@ def parse(self, source: Any, ns_map: Dict[Optional[str], str]) -> Any: class EventsHandler(XmlHandler): """Sax content handler for pre-recorded events.""" - def parse(self, source: List[Tuple], ns_map: Dict[Optional[str], str]) -> Any: + def parse(self, source: list[tuple], ns_map: dict[Optional[str], str]) -> Any: """Forward the pre-recorded events to the main parser. Args: diff --git a/xsdata/formats/dataclass/parsers/nodes/element.py b/xsdata/formats/dataclass/parsers/nodes/element.py index 1a2808086..a6a6ce78a 100644 --- a/xsdata/formats/dataclass/parsers/nodes/element.py +++ b/xsdata/formats/dataclass/parsers/nodes/element.py @@ -1,6 +1,5 @@ -import math from itertools import starmap -from typing import Any, Dict, List, Optional, Set, Type +from typing import Any, Optional from xsdata.exceptions import ParserError from xsdata.formats.converter import converter @@ -54,13 +53,13 @@ class ElementNode(XmlNode): def __init__( self, meta: XmlMeta, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, config: ParserConfig, context: XmlContext, position: int, mixed: bool = False, - derived_factory: Optional[Type] = None, + derived_factory: Optional[type] = None, xsi_type: Optional[str] = None, xsi_nil: Optional[bool] = None, ): @@ -74,7 +73,7 @@ def __init__( self.derived_factory = derived_factory self.xsi_type = xsi_type self.xsi_nil = xsi_nil - self.assigned: Set[int] = set() + self.assigned: set[int] = set() self.tail_processed: bool = False def bind( @@ -82,7 +81,7 @@ def bind( qname: str, text: Optional[str], tail: Optional[str], - objects: List[Any], + objects: list[Any], ) -> bool: """Bind the parsed data into an object for the ending element. @@ -101,7 +100,7 @@ def bind( """ obj: Any = None if not self.xsi_nil or self.meta.nillable: - params: Dict = {} + params: dict = {} self.bind_attrs(params) self.bind_content(params, text, tail, objects) obj = self.config.class_factory(self.meta.clazz, params) @@ -120,10 +119,10 @@ def bind( def bind_content( self, - params: Dict, + params: dict, text: Optional[str], tail: Optional[str], - objects: List[Any], + objects: list[Any], ): """Parse the text and tail content. @@ -149,7 +148,7 @@ def bind_content( if isinstance(params[key], PendingCollection): params[key] = params[key].evaluate() - def bind_attrs(self, params: Dict[str, Any]): + def bind_attrs(self, params: dict[str, Any]): """Parse the element attributes. Scenarios: @@ -183,7 +182,7 @@ def bind_attrs(self, params: Dict[str, Any]): f"Unknown attribute {self.meta.qname}:{qname}" ) - def bind_attr(self, params: Dict, var: XmlVar, value: Any): + def bind_attr(self, params: dict, var: XmlVar, value: Any): """Parse an element attribute. Ignores fields with init==false! @@ -206,7 +205,7 @@ def bind_attr(self, params: Dict, var: XmlVar, value: Any): else: ParserUtils.validate_fixed_value(self.meta, var, value) - def bind_any_attr(self, params: Dict, var: XmlVar, qname: str, value: Any): + def bind_any_attr(self, params: dict, var: XmlVar, qname: str, value: Any): """Parse an element attribute to a wildcard field. Args: @@ -220,7 +219,7 @@ def bind_any_attr(self, params: Dict, var: XmlVar, qname: str, value: Any): params[var.name][qname] = ParserUtils.parse_any_attribute(value, self.ns_map) - def bind_objects(self, params: Dict, objects: List): + def bind_objects(self, params: dict, objects: list): """Bind children objects. Emit a warning if an object doesn't fit in any @@ -237,7 +236,7 @@ class parameters. del objects[position:] - def bind_object(self, params: Dict, qname: str, value: Any) -> bool: + def bind_object(self, params: dict, qname: str, value: Any) -> bool: """Bind a child object. Args: @@ -259,7 +258,7 @@ def bind_object(self, params: Dict, qname: str, value: Any) -> bool: return False @classmethod - def bind_var(cls, params: Dict, var: XmlVar, value: Any) -> bool: + def bind_var(cls, params: dict, var: XmlVar, value: Any) -> bool: """Bind a child object to an element field. Args: @@ -285,7 +284,7 @@ def bind_var(cls, params: Dict, var: XmlVar, value: Any) -> bool: return True - def bind_wild_var(self, params: Dict, var: XmlVar, qname: str, value: Any) -> bool: + def bind_wild_var(self, params: dict, var: XmlVar, qname: str, value: Any) -> bool: """Bind a child object to a wildcard field. The wildcard might support one or more values. If it @@ -322,7 +321,7 @@ def bind_wild_var(self, params: Dict, var: XmlVar, qname: str, value: Any) -> bo return True - def bind_mixed_objects(self, params: Dict, var: XmlVar, objects: List): + def bind_mixed_objects(self, params: dict, var: XmlVar, objects: list): """Bind children objects to a mixed content wildcard field. Args: @@ -351,7 +350,7 @@ def prepare_generic_value(self, qname: Optional[str], value: Any) -> Any: return value - def bind_text(self, params: Dict, text: Optional[str]) -> bool: + def bind_text(self, params: dict, text: Optional[str]) -> bool: """Bind the element text content. Args: @@ -387,7 +386,7 @@ def bind_text(self, params: Dict, text: Optional[str]) -> bool: def bind_wild_text( self, - params: Dict, + params: dict, var: XmlVar, text: Optional[str], tail: Optional[str], @@ -438,7 +437,7 @@ def bind_wild_text( return True - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Initialize the next child node to be queued, when an element starts. This entry point is responsible to create the next node type @@ -474,8 +473,8 @@ def build_node( self, qname: str, var: XmlVar, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, position: int, ) -> Optional[XmlNode]: """Build the next child node based on the xml var instance. @@ -585,13 +584,13 @@ def build_node( def build_element_node( self, - clazz: Type, + clazz: type, derived: bool, nillable: bool, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, position: int, - derived_factory: Type, + derived_factory: type, xsi_type: Optional[str] = None, xsi_nil: Optional[bool] = None, ) -> Optional["ElementNode"]: diff --git a/xsdata/formats/dataclass/parsers/nodes/primitive.py b/xsdata/formats/dataclass/parsers/nodes/primitive.py index f915d416a..fb7fc5434 100644 --- a/xsdata/formats/dataclass/parsers/nodes/primitive.py +++ b/xsdata/formats/dataclass/parsers/nodes/primitive.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional +from typing import Optional from xsdata.exceptions import XmlContextError from xsdata.formats.dataclass.models.elements import XmlMeta, XmlVar @@ -19,7 +19,7 @@ class PrimitiveNode(XmlNode): __slots__ = "meta", "var", "ns_map", "config" - def __init__(self, meta: XmlMeta, var: XmlVar, ns_map: Dict, config: ParserConfig): + def __init__(self, meta: XmlMeta, var: XmlVar, ns_map: dict, config: ParserConfig): self.meta = meta self.var = var self.ns_map = ns_map @@ -30,7 +30,7 @@ def bind( qname: str, text: Optional[str], tail: Optional[str], - objects: List, + objects: list, ) -> bool: """Bind the parsed data into an object for the ending element. @@ -67,6 +67,6 @@ def bind( return True - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Raise an exception if there is a child element inside this node.""" raise XmlContextError("Primitive node doesn't support child nodes!") diff --git a/xsdata/formats/dataclass/parsers/nodes/skip.py b/xsdata/formats/dataclass/parsers/nodes/skip.py index 2044c2538..60753d652 100644 --- a/xsdata/formats/dataclass/parsers/nodes/skip.py +++ b/xsdata/formats/dataclass/parsers/nodes/skip.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional +from typing import Optional from xsdata.formats.dataclass.parsers.mixins import XmlNode @@ -11,12 +11,12 @@ class SkipNode(XmlNode): def __init__(self): self.ns_map = {} - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Skip nodes children are skipped as well.""" return self def bind( - self, qname: str, text: Optional[str], tail: Optional[str], objects: List + self, qname: str, text: Optional[str], tail: Optional[str], objects: list ) -> bool: """Skip nodes are not building any objects.""" return False diff --git a/xsdata/formats/dataclass/parsers/nodes/standard.py b/xsdata/formats/dataclass/parsers/nodes/standard.py index d919e0e5d..f765a8cab 100644 --- a/xsdata/formats/dataclass/parsers/nodes/standard.py +++ b/xsdata/formats/dataclass/parsers/nodes/standard.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Type +from typing import Optional from xsdata.exceptions import XmlContextError from xsdata.formats.dataclass.models.elements import XmlMeta, XmlVar @@ -36,10 +36,10 @@ def __init__( meta: XmlMeta, var: XmlVar, datatype: DataType, - ns_map: Dict, + ns_map: dict, config: ParserConfig, nillable: bool, - derived_factory: Optional[Type], + derived_factory: Optional[type], ): self.meta = meta self.var = var @@ -54,7 +54,7 @@ def bind( qname: str, text: Optional[str], tail: Optional[str], - objects: List, + objects: list, ) -> bool: """Bind the parsed data into an object for the ending element. @@ -93,6 +93,6 @@ def bind( objects.append((qname, obj)) return True - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Raise an exception if there is a child element inside this node.""" raise XmlContextError("StandardNode node doesn't support child nodes!") diff --git a/xsdata/formats/dataclass/parsers/nodes/union.py b/xsdata/formats/dataclass/parsers/nodes/union.py index b1e9b5070..ca56a82a4 100644 --- a/xsdata/formats/dataclass/parsers/nodes/union.py +++ b/xsdata/formats/dataclass/parsers/nodes/union.py @@ -2,7 +2,7 @@ import functools from contextlib import suppress from dataclasses import replace -from typing import Any, Dict, List, Optional, Tuple, Type +from typing import Any, Optional from xsdata.exceptions import ParserError from xsdata.formats.dataclass.context import XmlContext @@ -48,8 +48,8 @@ def __init__( self, meta: XmlMeta, var: XmlVar, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, position: int, config: ParserConfig, context: XmlContext, @@ -63,9 +63,9 @@ def __init__( self.context = context self.level = 0 self.candidates = self.filter_candidates() - self.events: List[Tuple[str, str, Any, Any]] = [] + self.events: list[tuple[str, str, Any, Any]] = [] - def filter_candidates(self) -> List[Type]: + def filter_candidates(self) -> list[type]: """Filter union candidates by fixed attributes.""" candidates = list(self.var.types) fixed_attribute = functools.partial( @@ -74,7 +74,7 @@ def filter_candidates(self) -> List[Type]: return list(filter(fixed_attribute, candidates)) - def filter_fixed_attrs(self, candidate: Type, parent_ns: Optional[str]) -> bool: + def filter_fixed_attrs(self, candidate: type, parent_ns: Optional[str]) -> bool: """Return whether the node attrs are incompatible with fixed attrs. Args: @@ -97,7 +97,7 @@ def filter_fixed_attrs(self, candidate: Type, parent_ns: Optional[str]) -> bool: return True - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Record the event for the child element. This entry point records all events, as it's not possible @@ -120,7 +120,7 @@ def bind( qname: str, text: Optional[str], tail: Optional[str], - objects: List, + objects: list, ) -> bool: """Bind the parsed data into an object for the ending element. diff --git a/xsdata/formats/dataclass/parsers/nodes/wildcard.py b/xsdata/formats/dataclass/parsers/nodes/wildcard.py index 34ca69029..ca8e898c1 100644 --- a/xsdata/formats/dataclass/parsers/nodes/wildcard.py +++ b/xsdata/formats/dataclass/parsers/nodes/wildcard.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional, Type +from typing import Optional from xsdata.formats.dataclass.models.elements import XmlVar from xsdata.formats.dataclass.parsers.mixins import XmlNode @@ -26,10 +26,10 @@ class WildcardNode(XmlNode): def __init__( self, var: XmlVar, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, position: int, - factory: Type, + factory: type, ): self.var = var self.attrs = attrs @@ -38,7 +38,7 @@ def __init__( self.factory = factory def bind( - self, qname: str, text: Optional[str], tail: Optional[str], objects: List + self, qname: str, text: Optional[str], tail: Optional[str], objects: list ) -> bool: """Bind the parsed data into a generic element. @@ -78,7 +78,7 @@ def bind( return True @classmethod - def fetch_any_children(cls, position: int, objects: List) -> List: + def fetch_any_children(cls, position: int, objects: list) -> list: """Fetch the children of this node in the objects list. The children are removed from the objects list. @@ -96,7 +96,7 @@ def fetch_any_children(cls, position: int, objects: List) -> List: return children - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Initialize the next child wildcard node to be queued, when an element starts. This entry point is responsible to create the next node type diff --git a/xsdata/formats/dataclass/parsers/nodes/wrapper.py b/xsdata/formats/dataclass/parsers/nodes/wrapper.py index ec65942d5..de6bc998f 100644 --- a/xsdata/formats/dataclass/parsers/nodes/wrapper.py +++ b/xsdata/formats/dataclass/parsers/nodes/wrapper.py @@ -1,4 +1,4 @@ -from typing import Dict, List, Optional +from typing import Optional from xsdata.formats.dataclass.parsers.mixins import XmlNode from xsdata.formats.dataclass.parsers.nodes.element import ElementNode @@ -26,7 +26,7 @@ def __init__(self, parent: ElementNode): self.ns_map = parent.ns_map def bind( - self, qname: str, text: Optional[str], tail: Optional[str], objects: List + self, qname: str, text: Optional[str], tail: Optional[str], objects: list ) -> bool: """This node will never appear in the xml, so it never binds any data. @@ -41,7 +41,7 @@ def bind( """ return False - def child(self, qname: str, attrs: Dict, ns_map: Dict, position: int) -> XmlNode: + def child(self, qname: str, attrs: dict, ns_map: dict, position: int) -> XmlNode: """Proxy the next child node to the parent node. Args: diff --git a/xsdata/formats/dataclass/parsers/tree.py b/xsdata/formats/dataclass/parsers/tree.py index 72132f013..7d9c35e0f 100644 --- a/xsdata/formats/dataclass/parsers/tree.py +++ b/xsdata/formats/dataclass/parsers/tree.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Dict, List, Optional, Type +from typing import Optional from xsdata.formats.dataclass.models.elements import XmlType, XmlVar from xsdata.formats.dataclass.parsers.bases import NodeParser, Parsed @@ -13,16 +13,16 @@ class TreeParser(NodeParser): """Bind xml nodes to a tree of AnyElement objects.""" - handler: Type[XmlHandler] = field(default=default_handler()) + handler: type[XmlHandler] = field(default=default_handler()) def start( self, - clazz: Optional[Type], - queue: List[XmlNode], - objects: List[Parsed], + clazz: Optional[type], + queue: list[XmlNode], + objects: list[Parsed], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, ): """Build and queue the XmlNode for the starting element. diff --git a/xsdata/formats/dataclass/parsers/utils.py b/xsdata/formats/dataclass/parsers/utils.py index 1c3b1ba41..9e5093e91 100644 --- a/xsdata/formats/dataclass/parsers/utils.py +++ b/xsdata/formats/dataclass/parsers/utils.py @@ -1,7 +1,8 @@ import math import warnings from collections import UserList -from typing import Any, Callable, Dict, Iterable, Optional, Sequence, Type +from collections.abc import Iterable, Sequence +from typing import Any, Callable, Optional from xsdata.exceptions import ConverterError, ConverterWarning, ParserError from xsdata.formats.converter import QNameConverter, converter @@ -49,7 +50,7 @@ class ParserUtils: """Random parser util functions.""" @classmethod - def xsi_type(cls, attrs: Dict, ns_map: Dict) -> Optional[str]: + def xsi_type(cls, attrs: dict, ns_map: dict) -> Optional[str]: """Parse the xsi:type attribute value if present. Args: @@ -67,7 +68,7 @@ def xsi_type(cls, attrs: Dict, ns_map: Dict) -> Optional[str]: return build_qname(namespace, name) @classmethod - def xsi_nil(cls, attrs: Dict) -> Optional[bool]: + def xsi_nil(cls, attrs: dict) -> Optional[bool]: """Return whether xsi:nil attribute value. Args: @@ -86,9 +87,9 @@ def parse_var( var: XmlVar, config: ParserConfig, value: Any, - ns_map: Optional[Dict] = None, + ns_map: Optional[dict] = None, default: Any = None, - types: Optional[Sequence[Type]] = None, + types: Optional[Sequence[type]] = None, tokens_factory: Optional[Callable] = None, format: Optional[str] = None, ) -> Any: @@ -130,9 +131,9 @@ def parse_var( def parse_value( cls, value: Any, - types: Sequence[Type], + types: Sequence[type], default: Optional[Any] = None, - ns_map: Optional[Dict] = None, + ns_map: Optional[dict] = None, tokens_factory: Optional[Callable] = None, format: Optional[str] = None, ) -> Any: @@ -185,8 +186,8 @@ def normalize_content(cls, value: Optional[str]) -> Optional[str]: @classmethod def parse_any_attributes( - cls, attrs: Dict[str, str], ns_map: Dict[Optional[str], str] - ) -> Dict[str, str]: + cls, attrs: dict[str, str], ns_map: dict[Optional[str], str] + ) -> dict[str, str]: """Parse attributes with qname support. Example: @@ -205,7 +206,7 @@ def parse_any_attributes( } @classmethod - def parse_any_attribute(cls, value: str, ns_map: Dict) -> str: + def parse_any_attribute(cls, value: str, ns_map: dict) -> str: """Expand the value with the full namespace if it has a prefix. Args: diff --git a/xsdata/formats/dataclass/parsers/xml.py b/xsdata/formats/dataclass/parsers/xml.py index 1a77fa429..da37a08f2 100644 --- a/xsdata/formats/dataclass/parsers/xml.py +++ b/xsdata/formats/dataclass/parsers/xml.py @@ -1,5 +1,5 @@ from dataclasses import dataclass, field -from typing import Any, Dict, List, Optional, Type +from typing import Any, Optional from xsdata.formats.dataclass.parsers.bases import NodeParser, Parsed from xsdata.formats.dataclass.parsers.handlers import default_handler @@ -22,7 +22,7 @@ class XmlParser(NodeParser): ns_map: The parsed namespace prefix-URI map """ - handler: Type[XmlHandler] = field(default=default_handler()) + handler: type[XmlHandler] = field(default=default_handler()) @dataclass @@ -44,17 +44,17 @@ class UserXmlParser(NodeParser): on duplicate events. """ - handler: Type[XmlHandler] = field(default=default_handler()) - hooks_cache: Dict = field(init=False, default_factory=dict) + handler: type[XmlHandler] = field(default=default_handler()) + hooks_cache: dict = field(init=False, default_factory=dict) def start( self, - clazz: Optional[Type], - queue: List[XmlNode], - objects: List[Parsed], + clazz: Optional[type], + queue: list[XmlNode], + objects: list[Parsed], qname: str, - attrs: Dict, - ns_map: Dict, + attrs: dict, + ns_map: dict, ): """Build and queue the XmlNode for the starting element. @@ -73,8 +73,8 @@ def start( def end( self, - queue: List[XmlNode], - objects: List[Parsed], + queue: list[XmlNode], + objects: list[Parsed], qname: str, text: Optional[str], tail: Optional[str], diff --git a/xsdata/formats/dataclass/serializers/code.py b/xsdata/formats/dataclass/serializers/code.py index d9183d067..44ecb91be 100644 --- a/xsdata/formats/dataclass/serializers/code.py +++ b/xsdata/formats/dataclass/serializers/code.py @@ -1,7 +1,8 @@ +from collections.abc import Iterator, Mapping from dataclasses import dataclass, field from enum import Enum from io import StringIO -from typing import Any, Iterator, List, Mapping, Set, TextIO, Tuple, Type, Union +from typing import Any, TextIO, Union from xsdata.formats.dataclass.context import XmlContext from xsdata.utils import collections @@ -47,7 +48,7 @@ def write(self, out: TextIO, obj: Any, var_name: str): obj: The input model instance to serialize var_name: The var name to assign the model instance """ - types: Set[Type] = set() + types: set[type] = set() tmp = StringIO() for chunk in self.repr_object(obj, 0, types): @@ -61,7 +62,7 @@ def write(self, out: TextIO, obj: Any, var_name: str): out.write("\n") @classmethod - def build_imports(cls, types: Set[Type]) -> str: + def build_imports(cls, types: set[type]) -> str: """Build a list of imports from the given types. Args: @@ -82,7 +83,7 @@ def build_imports(cls, types: Set[Type]) -> str: return "".join(sorted(imports)) - def repr_object(self, obj: Any, level: int, types: Set[Type]) -> Iterator[str]: + def repr_object(self, obj: Any, level: int, types: set[type]) -> Iterator[str]: """Write the given object as repr code. Args: @@ -107,9 +108,9 @@ def repr_object(self, obj: Any, level: int, types: Set[Type]) -> Iterator[str]: def repr_array( self, - obj: Union[List, Set, Tuple], + obj: Union[list, set, tuple], level: int, - types: Set[Type], + types: set[type], ) -> Iterator[str]: """Convert an iterable object to repr code. @@ -134,7 +135,7 @@ def repr_array( yield f"{spaces * level}]" - def repr_mapping(self, obj: Mapping, level: int, types: Set[Type]) -> Iterator[str]: + def repr_mapping(self, obj: Mapping, level: int, types: set[type]) -> Iterator[str]: """Convert a map object to repr code. Args: @@ -160,7 +161,7 @@ def repr_mapping(self, obj: Mapping, level: int, types: Set[Type]) -> Iterator[s yield f"{spaces * level}}}" - def repr_model(self, obj: Any, level: int, types: Set[Type]) -> Iterator[str]: + def repr_model(self, obj: Any, level: int, types: set[type]) -> Iterator[str]: """Convert a data model instance to repr code. Args: diff --git a/xsdata/formats/dataclass/serializers/config.py b/xsdata/formats/dataclass/serializers/config.py index b3ae555dd..28a011280 100644 --- a/xsdata/formats/dataclass/serializers/config.py +++ b/xsdata/formats/dataclass/serializers/config.py @@ -1,6 +1,6 @@ import warnings from dataclasses import InitVar, dataclass -from typing import Any, Callable, Dict, Optional +from typing import Any, Callable, Optional @dataclass @@ -28,7 +28,7 @@ class SerializerConfig: ignore_default_attributes: bool = False schema_location: Optional[str] = None no_namespace_schema_location: Optional[str] = None - globalns: Optional[Dict[str, Callable]] = None + globalns: Optional[dict[str, Callable]] = None # Deprecated pretty_print: InitVar[bool] = False diff --git a/xsdata/formats/dataclass/serializers/dict.py b/xsdata/formats/dataclass/serializers/dict.py index 0996cde2b..8afe9e949 100644 --- a/xsdata/formats/dataclass/serializers/dict.py +++ b/xsdata/formats/dataclass/serializers/dict.py @@ -1,6 +1,7 @@ +from collections.abc import Iterator from dataclasses import dataclass, field from enum import Enum -from typing import Any, Callable, Dict, Iterator, Optional, Tuple +from typing import Any, Callable, Optional from xsdata.formats.converter import converter from xsdata.formats.dataclass.context import XmlContext @@ -9,7 +10,7 @@ from xsdata.utils import collections -def filter_none(x: Tuple) -> Dict: +def filter_none(x: tuple) -> dict: """Convert a key-value pairs to dict, ignoring None values. Args: @@ -80,7 +81,7 @@ def encode( return converter.serialize(value, format=var.format) - def next_value(self, obj: Any) -> Iterator[Tuple[str, Any]]: + def next_value(self, obj: Any) -> Iterator[tuple[str, Any]]: """Fetch the next value of a model instance to convert. Args: diff --git a/xsdata/formats/dataclass/serializers/mixins.py b/xsdata/formats/dataclass/serializers/mixins.py index 3e7c31fc5..33531616f 100644 --- a/xsdata/formats/dataclass/serializers/mixins.py +++ b/xsdata/formats/dataclass/serializers/mixins.py @@ -1,18 +1,14 @@ import abc from abc import ABC +from collections.abc import Iterable, Iterator from dataclasses import dataclass, field from enum import Enum from typing import ( Any, - Dict, Final, - Iterable, - Iterator, - List, Literal, Optional, TextIO, - Tuple, Union, ) from xml.etree.ElementTree import QName @@ -42,10 +38,10 @@ class XmlWriterEvent: END: Final = "end" -StartEvent: TypeAlias = Tuple[Literal["start"], str] -AttrEvent: TypeAlias = Tuple[Literal["attr"], str, Any] -DataEvent: TypeAlias = Tuple[Literal["data"], str] -EndEvent: TypeAlias = Tuple[Literal["end"], str] +StartEvent: TypeAlias = tuple[Literal["start"], str] +AttrEvent: TypeAlias = tuple[Literal["attr"], str, Any] +DataEvent: TypeAlias = tuple[Literal["data"], str] +EndEvent: TypeAlias = tuple[Literal["end"], str] EventIterator = Iterator[Union[StartEvent, AttrEvent, DataEvent, EndEvent]] @@ -78,16 +74,16 @@ class EventHandler(abc.ABC): "pending_prefixes", ) - def __init__(self, config: SerializerConfig, ns_map: Dict): + def __init__(self, config: SerializerConfig, ns_map: dict): self.config = config self.ns_map = ns_map self.in_tail = False self.tail: Optional[str] = None - self.attrs: Dict = {} - self.ns_context: List[Dict] = [] - self.pending_tag: Optional[Tuple] = None - self.pending_prefixes: List[List] = [] + self.attrs: dict = {} + self.ns_context: list[dict] = [] + self.pending_tag: Optional[tuple] = None + self.pending_prefixes: list[list] = [] def write(self, events: EventIterator): """Feed the sax content handler with events. @@ -268,7 +264,7 @@ def start_namespaces(self): Save the list of prefixes to be removed at the end of the current pending tag. """ - prefixes: List[str] = [] + prefixes: list[str] = [] self.pending_prefixes.append(prefixes) try: @@ -328,7 +324,7 @@ def end_document(self): """End document notification receiver.""" @abc.abstractmethod - def start_element(self, name: Tuple[str, str], qname: str, attrs: Dict): + def start_element(self, name: tuple[str, str], qname: str, attrs: dict): """Start element notification receiver. Args: @@ -338,7 +334,7 @@ def start_element(self, name: Tuple[str, str], qname: str, attrs: Dict): """ @abc.abstractmethod - def end_element(self, name: Tuple[str, str], qname: str): + def end_element(self, name: tuple[str, str], qname: str): """End element notification receiver. Args: @@ -389,7 +385,7 @@ class EventContentHandler(EventHandler): pending_prefixes: The pending element namespace prefixes """ - def __init__(self, config: SerializerConfig, ns_map: Dict): + def __init__(self, config: SerializerConfig, ns_map: dict): super().__init__(config, ns_map) self.handler = self.build_handler() @@ -413,7 +409,7 @@ def end_document(self): """End document entrypoint.""" self.handler.endDocument() - def end_element(self, name: Tuple[str, str], qname: str): + def end_element(self, name: tuple[str, str], qname: str): """End element notification receiver. Args: @@ -438,7 +434,7 @@ def end_prefix_mapping(self, prefix: str): """ self.handler.endPrefixMapping(prefix) - def start_element(self, name: Tuple[str, str], qname: str, attrs: Dict): + def start_element(self, name: tuple[str, str], qname: str, attrs: dict): """Start element notification receiver. Args: @@ -476,7 +472,7 @@ class XmlWriter(EventContentHandler, ABC): pending_prefixes: The pending element namespace prefixes """ - def __init__(self, config: SerializerConfig, output: TextIO, ns_map: Dict): + def __init__(self, config: SerializerConfig, output: TextIO, ns_map: dict): self.output = output super().__init__(config, ns_map) @@ -674,7 +670,7 @@ def convert_tokens( def convert_mixed_content( self, - values: List, + values: list, var: XmlVar, namespace: Optional[str], ) -> EventIterator: @@ -909,7 +905,7 @@ def convert_data(cls, value: Any, var: XmlVar) -> EventIterator: yield XmlWriterEvent.DATA, cls.encode_primitive(value, var) @classmethod - def next_value(cls, obj: Any, meta: XmlMeta) -> Iterator[Tuple[XmlVar, Any]]: + def next_value(cls, obj: Any, meta: XmlMeta) -> Iterator[tuple[XmlVar, Any]]: """Produce the next non attribute value of a model instance to convert. The generator will produce the values in the order the fields @@ -972,7 +968,7 @@ def next_attribute( nillable: bool, xsi_type: Optional[str], ignore_optionals: bool, - ) -> Iterator[Tuple[str, Any]]: + ) -> Iterator[tuple[str, Any]]: """Produce the next attribute value to convert. Args: diff --git a/xsdata/formats/dataclass/serializers/tree.py b/xsdata/formats/dataclass/serializers/tree.py index 61d993532..975f5b277 100644 --- a/xsdata/formats/dataclass/serializers/tree.py +++ b/xsdata/formats/dataclass/serializers/tree.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Any, Dict, Optional +from typing import Any, Optional from lxml.etree import ElementTree @@ -17,7 +17,7 @@ class TreeSerializer(EventGenerator): context: The models context instance """ - def render(self, obj: Any, ns_map: Optional[Dict] = None) -> ElementTree: + def render(self, obj: Any, ns_map: Optional[dict] = None) -> ElementTree: """Serialize the input model instance to a lxml etree instance. Args: diff --git a/xsdata/formats/dataclass/serializers/writers/__init__.py b/xsdata/formats/dataclass/serializers/writers/__init__.py index b8e3320f3..4bcf63605 100644 --- a/xsdata/formats/dataclass/serializers/writers/__init__.py +++ b/xsdata/formats/dataclass/serializers/writers/__init__.py @@ -1,5 +1,3 @@ -from typing import Type - from xsdata.formats.dataclass.serializers.mixins import XmlWriter from xsdata.formats.dataclass.serializers.writers.native import ( XmlEventWriter, @@ -8,7 +6,7 @@ try: from xsdata.formats.dataclass.serializers.writers.lxml import LxmlEventWriter - DEFAULT_XML_WRITER: Type[XmlWriter] = LxmlEventWriter + DEFAULT_XML_WRITER: type[XmlWriter] = LxmlEventWriter except ImportError: # pragma: no cover DEFAULT_XML_WRITER = XmlEventWriter diff --git a/xsdata/formats/dataclass/serializers/writers/lxml.py b/xsdata/formats/dataclass/serializers/writers/lxml.py index a3bb8f98a..e327cf5b4 100644 --- a/xsdata/formats/dataclass/serializers/writers/lxml.py +++ b/xsdata/formats/dataclass/serializers/writers/lxml.py @@ -1,4 +1,4 @@ -from typing import Iterator +from collections.abc import Iterator from lxml import etree from lxml.sax import ElementTreeContentHandler diff --git a/xsdata/formats/dataclass/serializers/writers/native.py b/xsdata/formats/dataclass/serializers/writers/native.py index be528d315..c4b1388f1 100644 --- a/xsdata/formats/dataclass/serializers/writers/native.py +++ b/xsdata/formats/dataclass/serializers/writers/native.py @@ -1,4 +1,4 @@ -from typing import Dict, TextIO +from typing import TextIO from xml.sax.saxutils import XMLGenerator from xsdata.formats.dataclass.serializers.config import SerializerConfig @@ -28,7 +28,7 @@ class XmlEventWriter(XmlWriter): __slots__ = ("current_level", "pending_end_element") - def __init__(self, config: SerializerConfig, output: TextIO, ns_map: Dict): + def __init__(self, config: SerializerConfig, output: TextIO, ns_map: dict): super().__init__(config, output, ns_map) self.current_level = 0 diff --git a/xsdata/formats/dataclass/serializers/xml.py b/xsdata/formats/dataclass/serializers/xml.py index e30868704..b2ae1141a 100644 --- a/xsdata/formats/dataclass/serializers/xml.py +++ b/xsdata/formats/dataclass/serializers/xml.py @@ -2,10 +2,8 @@ from io import StringIO from typing import ( Any, - Dict, Optional, TextIO, - Type, ) from xsdata.formats.dataclass.serializers.mixins import ( @@ -26,9 +24,9 @@ class XmlSerializer(EventGenerator): writer: The xml writer class """ - writer: Type[XmlWriter] = field(default=DEFAULT_XML_WRITER) + writer: type[XmlWriter] = field(default=DEFAULT_XML_WRITER) - def render(self, obj: Any, ns_map: Optional[Dict] = None) -> str: + def render(self, obj: Any, ns_map: Optional[dict] = None) -> str: """Serialize the input model instance to xml string. Args: @@ -42,7 +40,7 @@ def render(self, obj: Any, ns_map: Optional[Dict] = None) -> str: self.write(output, obj, ns_map) return output.getvalue() - def write(self, out: TextIO, obj: Any, ns_map: Optional[Dict] = None): + def write(self, out: TextIO, obj: Any, ns_map: Optional[dict] = None): """Serialize the given object to the output text stream. Args: diff --git a/xsdata/formats/dataclass/transports.py b/xsdata/formats/dataclass/transports.py index 20adff162..78f7db694 100644 --- a/xsdata/formats/dataclass/transports.py +++ b/xsdata/formats/dataclass/transports.py @@ -1,5 +1,5 @@ import abc -from typing import Any, Dict, Optional +from typing import Any, Optional from requests import Response, Session @@ -10,11 +10,11 @@ class Transport(abc.ABC): __slots__ = () @abc.abstractmethod - def get(self, url: str, params: Dict, headers: Dict) -> bytes: + def get(self, url: str, params: dict, headers: dict) -> bytes: """Send a GET request.""" @abc.abstractmethod - def post(self, url: str, data: Any, headers: Dict) -> bytes: + def post(self, url: str, data: Any, headers: dict) -> bytes: """Send a POST request.""" @@ -31,7 +31,7 @@ def __init__(self, timeout: float = 2.0, session: Optional[Session] = None): self.timeout = timeout self.session = session or Session() - def get(self, url: str, params: Dict, headers: Dict) -> bytes: + def get(self, url: str, params: dict, headers: dict) -> bytes: """Send a GET request. Args: @@ -53,7 +53,7 @@ def get(self, url: str, params: Dict, headers: Dict) -> bytes: ) return self.handle_response(res) - def post(self, url: str, data: Any, headers: Dict) -> Any: + def post(self, url: str, data: Any, headers: dict) -> Any: """Send a POST request. Args: diff --git a/xsdata/formats/dataclass/typing.py b/xsdata/formats/dataclass/typing.py index b190c0bcc..c8fa645e3 100644 --- a/xsdata/formats/dataclass/typing.py +++ b/xsdata/formats/dataclass/typing.py @@ -5,8 +5,6 @@ Callable, NamedTuple, Optional, - Tuple, - Type, TypeVar, Union, ) @@ -66,12 +64,12 @@ def evaluate(tp: Any, globalns: Any, localns: Any = None) -> Any: class Result(NamedTuple): - types: Tuple[Type[Any], ...] + types: tuple[type[Any], ...] factory: Optional[Callable] = None tokens_factory: Optional[Callable] = None -def analyze_token_args(origin: Any, args: Tuple[Any, ...]) -> Tuple[Any]: +def analyze_token_args(origin: Any, args: tuple[Any, ...]) -> tuple[Any]: """Analyze token arguments. Ensure it only has one argument, filter out ellipsis. @@ -97,8 +95,8 @@ def analyze_token_args(origin: Any, args: Tuple[Any, ...]) -> Tuple[Any]: def analyze_optional_origin( - origin: Any, args: Tuple[Any, ...], types: Tuple[Any, ...] -) -> Tuple[Any, ...]: + origin: Any, args: tuple[Any, ...], types: tuple[Any, ...] +) -> tuple[Any, ...]: """Analyze optional type annotations. Remove the NoneType, adjust and return the origin, args and types. @@ -119,11 +117,11 @@ def analyze_optional_origin( return origin, args, types -def filter_none_type(args: Tuple[Any, ...]) -> Tuple[Any, ...]: +def filter_none_type(args: tuple[Any, ...]) -> tuple[Any, ...]: return tuple(arg for arg in args if arg is not NONE_TYPE) -def filter_ellipsis(args: Tuple[Any, ...]) -> Tuple[Any]: +def filter_ellipsis(args: tuple[Any, ...]) -> tuple[Any]: return tuple(arg for arg in args if arg is not Ellipsis) diff --git a/xsdata/formats/mixins.py b/xsdata/formats/mixins.py index dc978ca2c..32f66bc79 100644 --- a/xsdata/formats/mixins.py +++ b/xsdata/formats/mixins.py @@ -1,7 +1,8 @@ import abc import datetime +from collections.abc import Iterator from pathlib import Path -from typing import Dict, Iterator, List, NamedTuple +from typing import NamedTuple from xsdata import __version__ from xsdata.codegen.exceptions import CodegenError @@ -46,16 +47,16 @@ def package_name(self, package: str) -> str: return package @abc.abstractmethod - def render(self, classes: List[Class]) -> Iterator[GeneratorResult]: + def render(self, classes: list[Class]) -> Iterator[GeneratorResult]: """Return an iterator of the generated results.""" @classmethod - def group_by_package(cls, classes: List[Class]) -> Dict[Path, List[Class]]: + def group_by_package(cls, classes: list[Class]) -> dict[Path, list[Class]]: """Group the given list of classes by the target package directory.""" return group_by(classes, lambda x: package_path(x.target_module)) @classmethod - def group_by_module(cls, classes: List[Class]) -> Dict[Path, List[Class]]: + def group_by_module(cls, classes: list[Class]) -> dict[Path, list[Class]]: """Group the given list of classes by the target module directory.""" return group_by(classes, lambda x: module_path(x.target_module)) @@ -72,7 +73,7 @@ def render_header(self) -> str: '"""\n' ) - def normalize_packages(self, classes: List[Class]): + def normalize_packages(self, classes: list[Class]): """Normalize the classes module and package names. Args: diff --git a/xsdata/models/datatype.py b/xsdata/models/datatype.py index 703b65f5a..03324069f 100644 --- a/xsdata/models/datatype.py +++ b/xsdata/models/datatype.py @@ -2,7 +2,7 @@ import operator import re from collections import UserString -from typing import Any, Callable, Dict, NamedTuple, Optional, Union +from typing import Any, Callable, NamedTuple, Optional, Union from xsdata.utils.dates import ( calculate_offset, @@ -571,7 +571,7 @@ def _parse_interval(cls, value: str) -> TimeInterval: seconds=float(seconds) if seconds else None, ) - def asdict(self) -> Dict: + def asdict(self) -> dict: """Return instance as a dict.""" return self._interval._asdict() @@ -658,7 +658,7 @@ def _parse_period(cls, value: str) -> TimePeriod: return TimePeriod(year=year, month=month, day=day, offset=offset) - def as_dict(self) -> Dict: + def as_dict(self) -> dict: """Return date units as dict.""" return self._period._asdict() diff --git a/xsdata/models/dtd.py b/xsdata/models/dtd.py index 9e96e3ed0..a15ee102a 100644 --- a/xsdata/models/dtd.py +++ b/xsdata/models/dtd.py @@ -1,6 +1,6 @@ import enum from dataclasses import dataclass -from typing import Dict, List, Optional +from typing import Optional from xsdata.models.enums import DataType from xsdata.utils.namespaces import build_qname @@ -76,7 +76,7 @@ class DtdAttribute: type: DtdAttributeType default: DtdAttributeDefault default_value: Optional[str] - values: List[str] + values: list[str] @property def data_type(self) -> DataType: @@ -120,8 +120,8 @@ class DtdElement: type: DtdElementType prefix: Optional[str] content: Optional[DtdContent] - attributes: List[DtdAttribute] - ns_map: Dict + attributes: list[DtdAttribute] + ns_map: dict @property def qname(self) -> str: @@ -140,4 +140,4 @@ class Dtd: """ location: str - elements: List[DtdElement] + elements: list[DtdElement] diff --git a/xsdata/models/enums.py b/xsdata/models/enums.py index 5fd625de3..a547ddb14 100644 --- a/xsdata/models/enums.py +++ b/xsdata/models/enums.py @@ -2,7 +2,7 @@ from decimal import Decimal from enum import Enum from pathlib import Path -from typing import Any, Callable, Dict, Optional, Tuple, Type +from typing import Any, Callable, Optional from xml.etree.ElementTree import QName from xsdata.models.datatype import ( @@ -48,7 +48,7 @@ def get_enum(cls, uri: Optional[str]) -> Optional["Namespace"]: return __STANDARD_NAMESPACES__.get(uri) if uri else None @classmethod - def common(cls) -> Tuple["Namespace", ...]: + def common(cls) -> tuple["Namespace", ...]: """Return the common namespaces.""" return Namespace.XS, Namespace.XSI, Namespace.XML, Namespace.XLINK @@ -167,7 +167,7 @@ def __init__( code: str, python_type: type, fmt: Optional[str] = None, - wrapper: Optional[Type] = None, + wrapper: Optional[type] = None, ): self.code = code self.type = python_type @@ -193,7 +193,7 @@ def from_value(cls, value: Any) -> "DataType": return cls.from_type(_type) @classmethod - def from_type(cls, tp: Type) -> "DataType": + def from_type(cls, tp: type) -> "DataType": """Load from a python type.""" return __DataTypeIndex__.get(tp, DataType.STRING) @@ -251,7 +251,7 @@ def float_datatype(value: float) -> DataType: XmlHexBinary: DataType.HEX_BINARY, XmlBase64Binary: DataType.BASE64_BINARY, } -__DataTypeInferIndex__: Dict[Type, Callable] = { +__DataTypeInferIndex__: dict[type, Callable] = { int: int_datatype, float: float_datatype, XmlPeriod: period_datatype, diff --git a/xsdata/models/mixins.py b/xsdata/models/mixins.py index 44c560c82..adc36cc58 100644 --- a/xsdata/models/mixins.py +++ b/xsdata/models/mixins.py @@ -1,5 +1,6 @@ +from collections.abc import Iterator from dataclasses import dataclass, field, fields -from typing import Any, Callable, Dict, Iterator, List, Optional +from typing import Any, Callable, Optional from xsdata.codegen.exceptions import CodegenError from xsdata.formats.dataclass.models.elements import XmlType @@ -22,7 +23,7 @@ class ElementBase: init=False, metadata={"type": "Ignore"}, ) - ns_map: Dict[str, str] = field( + ns_map: dict[str, str] = field( default_factory=dict, init=False, metadata={"type": "Ignore"}, @@ -142,7 +143,7 @@ def attr_types(self) -> Iterator[str]: yield from () @property - def substitutions(self) -> List[str]: + def substitutions(self) -> list[str]: """Return the substitution groups of this element.""" return [] @@ -155,7 +156,7 @@ def xs_prefix(self) -> Optional[str]: return None - def get_restrictions(self) -> Dict[str, Any]: + def get_restrictions(self) -> dict[str, Any]: """Return the restrictions dictionary of this element.""" return {} @@ -193,7 +194,7 @@ def element(optional: bool = True, **kwargs: Any) -> Any: return field(metadata=metadata, **kwargs) -def add_default_value(params: Dict, optional: bool): +def add_default_value(params: dict, optional: bool): """Add the default value if it's missing and the optional flag is true.""" if optional and not ("default" in params or "default_factory" in params): params["default"] = None @@ -213,7 +214,7 @@ def array_any_element(**kwargs: Any) -> Any: return field(metadata=metadata, default_factory=list, **kwargs) -def extract_metadata(params: Dict, **kwargs: Any) -> Dict: +def extract_metadata(params: dict, **kwargs: Any) -> dict: """Remove dataclasses standard field properties and merge any additional.""" metadata = { key: params.pop(key) for key in list(params.keys()) if key not in FIELD_PARAMS diff --git a/xsdata/models/wsdl.py b/xsdata/models/wsdl.py index 04bd8e733..914d641e1 100644 --- a/xsdata/models/wsdl.py +++ b/xsdata/models/wsdl.py @@ -1,5 +1,6 @@ +from collections.abc import Iterator from dataclasses import dataclass, field -from typing import Dict, Iterator, List, Optional, TypeVar +from typing import Optional, TypeVar from xsdata.codegen.exceptions import CodegenError from xsdata.codegen.models import get_name @@ -18,7 +19,7 @@ class Documentation: elements: A list of generic any elements """ - elements: List[object] = array_any_element() + elements: list[object] = array_any_element() @dataclass @@ -35,7 +36,7 @@ class WsdlElement: name: str = attribute() documentation: Optional[Documentation] = element() location: Optional[str] = field(default=None, metadata={"type": "Ignore"}) - ns_map: Dict[str, str] = field( + ns_map: dict[str, str] = field( default_factory=dict, init=False, metadata={"type": "Ignore"} ) @@ -52,7 +53,7 @@ class ExtensibleElement(WsdlElement): extended: A list of generic elements """ - extended: List[object] = array_any_element() + extended: list[object] = array_any_element() @property def extended_elements(self) -> Iterator[AnyElement]: @@ -69,7 +70,7 @@ class Types: documentation: The type documentation """ - schemas: List[Schema] = array_element(name="schema", namespace=Namespace.XS.uri) + schemas: list[Schema] = array_element(name="schema", namespace=Namespace.XS.uri) documentation: Optional[Documentation] = element() @@ -115,7 +116,7 @@ class Message(WsdlElement): parts: The message parts """ - parts: List[Part] = array_element(name="part") + parts: list[Part] = array_element(name="part") @dataclass @@ -146,7 +147,7 @@ class PortTypeOperation(WsdlElement): input: PortTypeMessage = element() output: PortTypeMessage = element() - faults: List[PortTypeMessage] = array_element(name="fault") + faults: list[PortTypeMessage] = array_element(name="fault") @dataclass @@ -162,7 +163,7 @@ class PortType(ExtensibleElement): operations: The port type operations """ - operations: List[PortTypeOperation] = array_element(name="operation") + operations: list[PortTypeOperation] = array_element(name="operation") def find_operation(self, name: str) -> PortTypeOperation: """Find an operation by name or raise an error.""" @@ -199,7 +200,7 @@ class BindingOperation(ExtensibleElement): input: BindingMessage = element() output: BindingMessage = element() - faults: List[BindingMessage] = array_element(name="fault") + faults: list[BindingMessage] = array_element(name="fault") @dataclass @@ -217,7 +218,7 @@ class Binding(ExtensibleElement): """ type: str = attribute() - operations: List[BindingOperation] = array_element(name="operation") + operations: list[BindingOperation] = array_element(name="operation") def unique_operations(self) -> Iterator[BindingOperation]: """Yields all unique operation instances.""" @@ -255,7 +256,7 @@ class Service(WsdlElement): ports: The service ports """ - ports: List[ServicePort] = array_element(name="port") + ports: list[ServicePort] = array_element(name="port") @dataclass @@ -285,11 +286,11 @@ class Meta: target_namespace: Optional[str] = attribute(name="targetNamespace") types: Optional[Types] = element() - imports: List[Import] = array_element(name="import") - messages: List[Message] = array_element(name="message") - port_types: List[PortType] = array_element(name="portType") - bindings: List[Binding] = array_element(name="binding") - services: List[Service] = array_element(name="service") + imports: list[Import] = array_element(name="import") + messages: list[Message] = array_element(name="message") + port_types: list[PortType] = array_element(name="portType") + bindings: list[Binding] = array_element(name="binding") + services: list[Service] = array_element(name="service") @property def schemas(self) -> Iterator[Schema]: @@ -330,7 +331,7 @@ def included(self) -> Iterator[Import]: T = TypeVar("T", bound=WsdlElement) -def find_or_die(items: List[T], name: str, type_name: str) -> T: +def find_or_die(items: list[T], name: str, type_name: str) -> T: """Find an item by name or raise an error.""" for msg in items: if msg.name == name: diff --git a/xsdata/models/xsd.py b/xsdata/models/xsd.py index 134dd1b23..7d8d0d73c 100644 --- a/xsdata/models/xsd.py +++ b/xsdata/models/xsd.py @@ -1,9 +1,9 @@ import sys import textwrap +from collections.abc import Iterator from dataclasses import dataclass, field from typing import Any as Anything -from typing import Dict, Iterator, Optional -from typing import List as Array +from typing import Optional from typing import Union as UnionType from xsdata.formats.dataclass.serializers import XmlSerializer @@ -56,7 +56,7 @@ class Meta: namespace = "http://www.w3.org/1999/xhtml" - content: Array[object] = array_any_element() + content: list[object] = array_any_element() @dataclass @@ -66,7 +66,7 @@ class Documentation(ElementBase): lang: Optional[str] = attribute() source: Optional[str] = attribute() attributes: Optional["AnyAttribute"] = element() - content: Array[object] = array_any_element(mixed=True) + content: list[object] = array_any_element(mixed=True) def tostring(self) -> Optional[str]: """Convert the content to a help string.""" @@ -89,15 +89,15 @@ class Meta: source: Optional[str] = attribute() any_attribute: Optional["AnyAttribute"] = element(name="anyAttribute") - content: Array[object] = array_any_element(mixed=True) + content: list[object] = array_any_element(mixed=True) @dataclass class Annotation(ElementBase): """XSD Annotation model representation.""" - app_infos: Array[Appinfo] = array_element(name="appinfo") - documentations: Array[Documentation] = array_element(name="documentation") + app_infos: list[Appinfo] = array_element(name="appinfo") + documentations: list[Documentation] = array_element(name="documentation") any_attribute: Optional["AnyAttribute"] = element(name="anyAttribute") @@ -106,7 +106,7 @@ class AnnotationBase(ElementBase): """XSD AnnotationBase model representation.""" id: Optional[str] = attribute() - annotations: Array[Annotation] = array_element(name="annotation") + annotations: list[Annotation] = array_element(name="annotation") any_attribute: Optional["AnyAttribute"] = element(name="anyAttribute") @property @@ -199,7 +199,7 @@ def attr_types(self) -> Iterator[str]: elif self.union: yield from self.union.bases - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" if self.restriction: return self.restriction.get_restrictions() @@ -231,7 +231,7 @@ def attr_types(self) -> Iterator[str]: if self.item_type: yield self.item_type - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return {"tokens": True} @@ -241,7 +241,7 @@ class Union(AnnotationBase): """XSD Union model representation.""" member_types: Optional[str] = attribute(name="memberTypes") - simple_types: Array[SimpleType] = array_element(name="simpleType") + simple_types: list[SimpleType] = array_element(name="simpleType") @property def bases(self) -> Iterator[str]: @@ -268,7 +268,7 @@ def attr_types(self) -> Iterator[str]: if self.member_types: yield from self.member_types.split() - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" restrictions = {} for simple_type in self.simple_types: @@ -319,7 +319,7 @@ def default_type(self) -> str: datatype = DataType.STRING if self.fixed else DataType.ANY_SIMPLE_TYPE return datatype.prefixed(self.xs_prefix) - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" if self.use == UseType.REQUIRED: restrictions = {"min_occurs": 1, "max_occurs": 1} @@ -340,8 +340,8 @@ class AttributeGroup(AnnotationBase): ref: str = attribute(default="") name: Optional[str] = attribute() - attributes: Array[Attribute] = array_element(name="attribute") - attribute_groups: Array["AttributeGroup"] = array_element(name="attributeGroup") + attributes: list[Attribute] = array_element(name="attribute") + attribute_groups: list["AttributeGroup"] = array_element(name="attributeGroup") @property def is_property(self) -> bool: @@ -392,7 +392,7 @@ def attr_types(self) -> Iterator[str]: """Return the attr types for this element.""" yield DataType.ANY_TYPE.prefixed(self.xs_prefix) - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" max_occurs = sys.maxsize if self.max_occurs == "unbounded" else self.max_occurs @@ -409,15 +409,15 @@ class All(AnnotationBase): min_occurs: int = attribute(default=1, name="minOccurs") max_occurs: UnionType[str, int] = attribute(default=1, name="maxOccurs") - any: Array[Any] = array_element(name="any") - elements: Array["Element"] = array_element(name="element") - groups: Array["Group"] = array_element(name="group") + any: list[Any] = array_element(name="any") + elements: list["Element"] = array_element(name="element") + groups: list["Group"] = array_element(name="group") def __post_init__(self): """Post initialization validations.""" self.max_occurs = validate_max_occurs(self.min_occurs, self.max_occurs) - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return { "path": [("a", id(self), self.min_occurs, self.max_occurs)], @@ -430,17 +430,17 @@ class Sequence(AnnotationBase): min_occurs: int = attribute(default=1, name="minOccurs") max_occurs: UnionType[str, int] = attribute(default=1, name="maxOccurs") - elements: Array["Element"] = array_element(name="element") - groups: Array["Group"] = array_element(name="group") - choices: Array["Choice"] = array_element(name="choice") - sequences: Array["Sequence"] = array_element(name="sequence") - any: Array["Any"] = array_element() + elements: list["Element"] = array_element(name="element") + groups: list["Group"] = array_element(name="group") + choices: list["Choice"] = array_element(name="choice") + sequences: list["Sequence"] = array_element(name="sequence") + any: list["Any"] = array_element() def __post_init__(self): """Post initialization validations.""" self.max_occurs = validate_max_occurs(self.min_occurs, self.max_occurs) - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return { "path": [("s", id(self), self.min_occurs, self.max_occurs)], @@ -453,17 +453,17 @@ class Choice(AnnotationBase): min_occurs: int = attribute(default=1, name="minOccurs") max_occurs: UnionType[str, int] = attribute(default=1, name="maxOccurs") - elements: Array["Element"] = array_element(name="element") - groups: Array["Group"] = array_element(name="group") - choices: Array["Choice"] = array_element(name="choice") - sequences: Array[Sequence] = array_element(name="sequence") - any: Array["Any"] = array_element() + elements: list["Element"] = array_element(name="element") + groups: list["Group"] = array_element(name="group") + choices: list["Choice"] = array_element(name="choice") + sequences: list[Sequence] = array_element(name="sequence") + any: list["Any"] = array_element() def __post_init__(self): """Post initialization validations.""" self.max_occurs = validate_max_occurs(self.min_occurs, self.max_occurs) - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return { "path": [("c", id(self), self.min_occurs, self.max_occurs)], @@ -497,7 +497,7 @@ def attr_types(self) -> Iterator[str]: if self.ref: yield self.ref - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return { "path": [("g", id(self), self.min_occurs, self.max_occurs)], @@ -529,9 +529,9 @@ class Extension(AnnotationBase): sequence: Optional[Sequence] = element() any_attribute: Optional[AnyAttribute] = element(name="anyAttribute") open_content: Optional[OpenContent] = element(name="openContent") - attributes: Array[Attribute] = array_element(name="attribute") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") - assertions: Array[Assertion] = array_element(name="assert") + attributes: list[Attribute] = array_element(name="attribute") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") + assertions: list[Assertion] = array_element(name="assert") @property def bases(self) -> Iterator[str]: @@ -662,12 +662,12 @@ class Restriction(AnnotationBase): choice: Optional[Choice] = element() sequence: Optional[Sequence] = element() open_content: Optional[OpenContent] = element(name="openContent") - attributes: Array[Attribute] = array_element(name="attribute") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") - enumerations: Array[Enumeration] = array_element(name="enumeration") - asserts: Array[Assertion] = array_element(name="assert") - assertions: Array[Assertion] = array_element(name="assertion") - any_element: Array[object] = array_any_element() + attributes: list[Attribute] = array_element(name="attribute") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") + enumerations: list[Enumeration] = array_element(name="enumeration") + asserts: list[Assertion] = array_element(name="assert") + assertions: list[Assertion] = array_element(name="assertion") + any_element: list[object] = array_any_element() min_exclusive: Optional[MinExclusive] = element(name="minExclusive") min_inclusive: Optional[MinInclusive] = element(name="minInclusive") min_length: Optional[MinLength] = element(name="minLength") @@ -678,7 +678,7 @@ class Restriction(AnnotationBase): fraction_digits: Optional[FractionDigits] = element(name="fractionDigits") length: Optional[Length] = element() white_space: Optional[WhiteSpace] = element(name="whiteSpace") - patterns: Array[Pattern] = array_element(name="pattern") + patterns: list[Pattern] = array_element(name="pattern") explicit_timezone: Optional[ExplicitTimezone] = element(name="explicitTimezone") simple_type: Optional[SimpleType] = element(name="simpleType") @@ -701,7 +701,7 @@ def bases(self) -> Iterator[str]: if self.base: yield self.base - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" restrictions = {} if self.simple_type: @@ -766,9 +766,9 @@ class ComplexType(AnnotationBase): sequence: Optional[Sequence] = element() any_attribute: Optional[AnyAttribute] = element(name="anyAttribute") open_content: Optional[OpenContent] = element(name="openContent") - attributes: Array[Attribute] = array_element(name="attribute") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") - assertion: Array[Assertion] = array_element(name="assert") + attributes: list[Attribute] = array_element(name="attribute") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") + assertion: list[Assertion] = array_element(name="assert") abstract: bool = attribute(default=False) mixed: bool = attribute(default=False) default_attributes_apply: bool = attribute( @@ -806,7 +806,7 @@ class Unique(AnnotationBase): name: Optional[str] = attribute() ref: Optional[str] = attribute() selector: Optional[Selector] = element() - fields: Array[Field] = array_element(name="field") + fields: list[Field] = array_element(name="field") @dataclass @@ -816,7 +816,7 @@ class Key(AnnotationBase): name: Optional[str] = attribute() ref: Optional[str] = attribute() selector: Optional[Selector] = element() - fields: Array[Selector] = array_element(name="field") + fields: list[Selector] = array_element(name="field") @dataclass @@ -827,7 +827,7 @@ class Keyref(AnnotationBase): ref: Optional[str] = attribute() refer: Optional[str] = attribute() selector: Optional[Selector] = element() - fields: Array[Selector] = array_element(name="field") + fields: list[Selector] = array_element(name="field") @dataclass @@ -854,7 +854,7 @@ def bases(self) -> Iterator[str]: if self.type: yield self.type - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" return { "path": [("alt", id(self), 0, 1)], @@ -877,10 +877,10 @@ class Element(AnnotationBase): target_namespace: Optional[str] = attribute(name="targetNamespace") simple_type: Optional[SimpleType] = element(name="simpleType") complex_type: Optional[ComplexType] = element(name="complexType") - alternatives: Array[Alternative] = array_element(name="alternative") - uniques: Array[Unique] = array_element(name="unique") - keys: Array[Key] = array_element(name="key") - keyrefs: Array[Keyref] = array_element(name="keyref") + alternatives: list[Alternative] = array_element(name="alternative") + uniques: list[Unique] = array_element(name="unique") + keys: list[Key] = array_element(name="key") + keyrefs: list[Keyref] = array_element(name="keyref") min_occurs: int = attribute(default=1, name="minOccurs") max_occurs: UnionType[str, int] = attribute(default=1, name="maxOccurs") nillable: bool = attribute(default=False) @@ -927,11 +927,11 @@ def attr_types(self) -> Iterator[str]: yield from (alt.type for alt in self.alternatives if alt.type) @property - def substitutions(self) -> Array[str]: + def substitutions(self) -> list[str]: """Return a list of the substitution groups.""" return self.substitution_group.split() if self.substitution_group else [] - def get_restrictions(self) -> Dict[str, Anything]: + def get_restrictions(self) -> dict[str, Anything]: """Return the restrictions dictionary of this element.""" restrictions = { "min_occurs": self.min_occurs, @@ -978,10 +978,10 @@ class Redefine(AnnotationBase): """XSD Redefine model representation.""" schema_location: Optional[str] = attribute(name="schemaLocation") - simple_types: Array[SimpleType] = array_element(name="simpleType") - complex_types: Array[ComplexType] = array_element(name="complexType") - groups: Array[Group] = array_element(name="group") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") + simple_types: list[SimpleType] = array_element(name="simpleType") + complex_types: list[ComplexType] = array_element(name="complexType") + groups: list[Group] = array_element(name="group") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") location: Optional[str] = field(default=None, metadata={"type": "Ignore"}) @@ -990,13 +990,13 @@ class Override(AnnotationBase): """XSD Override model representation.""" schema_location: Optional[str] = attribute(name="schemaLocation") - simple_types: Array[SimpleType] = array_element(name="simpleType") - complex_types: Array[ComplexType] = array_element(name="complexType") - groups: Array[Group] = array_element(name="group") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") - elements: Array[Element] = array_element(name="element") - attributes: Array[Attribute] = array_element(name="attribute") - notations: Array[Notation] = array_element(name="notation") + simple_types: list[SimpleType] = array_element(name="simpleType") + complex_types: list[ComplexType] = array_element(name="complexType") + groups: list[Group] = array_element(name="group") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") + elements: list[Element] = array_element(name="element") + attributes: list[Attribute] = array_element(name="attribute") + notations: list[Notation] = array_element(name="notation") location: Optional[str] = field(default=None, metadata={"type": "Ignore"}) @@ -1028,18 +1028,18 @@ class Meta: default_open_content: Optional[DefaultOpenContent] = element( name="defaultOpenContent" ) - includes: Array[Include] = array_element(name="include") - imports: Array[Import] = array_element(name="import") - redefines: Array[Redefine] = array_element(name="redefine") - overrides: Array[Override] = array_element(name="override") - annotations: Array[Annotation] = array_element(name="annotation") - simple_types: Array[SimpleType] = array_element(name="simpleType") - complex_types: Array[ComplexType] = array_element(name="complexType") - groups: Array[Group] = array_element(name="group") - attribute_groups: Array[AttributeGroup] = array_element(name="attributeGroup") - elements: Array[Element] = array_element(name="element") - attributes: Array[Attribute] = array_element(name="attribute") - notations: Array[Notation] = array_element(name="notation") + includes: list[Include] = array_element(name="include") + imports: list[Import] = array_element(name="import") + redefines: list[Redefine] = array_element(name="redefine") + overrides: list[Override] = array_element(name="override") + annotations: list[Annotation] = array_element(name="annotation") + simple_types: list[SimpleType] = array_element(name="simpleType") + complex_types: list[ComplexType] = array_element(name="complexType") + groups: list[Group] = array_element(name="group") + attribute_groups: list[AttributeGroup] = array_element(name="attributeGroup") + elements: list[Element] = array_element(name="element") + attributes: list[Attribute] = array_element(name="attribute") + notations: list[Notation] = array_element(name="notation") location: Optional[str] = field(default=None, metadata={"type": "Ignore"}) def included(self) -> Iterator[UnionType[Import, Include, Redefine, Override]]: diff --git a/xsdata/utils/click.py b/xsdata/utils/click.py index 5baebe353..47746adac 100644 --- a/xsdata/utils/click.py +++ b/xsdata/utils/click.py @@ -1,14 +1,11 @@ import enum import inspect import logging +from collections.abc import Iterator from dataclasses import fields, is_dataclass from typing import ( Any, Callable, - Dict, - Iterator, - List, - Type, TypeVar, Union, get_type_hints, @@ -90,7 +87,7 @@ def build_options(obj: Any, parent: str) -> Iterator[Callable[[FC], FC]]: ) -def get_doc_hints(obj: Any) -> Dict[str, str]: +def get_doc_hints(obj: Any) -> dict[str, str]: """Return a param-docstring map of the class arguments.""" docstrings = inspect.getdoc(obj) assert docstrings is not None @@ -109,7 +106,7 @@ def get_doc_hints(obj: Any) -> Dict[str, str]: class EnumChoice(click.Choice): """Custom click choice widget for enumerations.""" - def __init__(self, enumeration: Type[enum.Enum]): + def __init__(self, enumeration: type[enum.Enum]): self.enumeration = enumeration super().__init__([e.value for e in enumeration]) @@ -121,7 +118,7 @@ def convert(self, value: Any, *args: Any) -> enum.Enum: class LogFormatter(logging.Formatter): """Custom log formatter with click colors.""" - colors: Dict[str, Any] = { + colors: dict[str, Any] = { "error": {"fg": "red"}, "exception": {"fg": "red"}, "critical": {"fg": "red"}, @@ -147,7 +144,7 @@ class LogHandler(logging.Handler): def __init__(self, level: Union[int, str] = logging.NOTSET): super().__init__(level) - self.warnings: List[str] = [] + self.warnings: list[str] = [] def emit(self, record: logging.LogRecord): """Override emit to record warnings.""" diff --git a/xsdata/utils/collections.py b/xsdata/utils/collections.py index ab1e8ec3b..9652c8aae 100644 --- a/xsdata/utils/collections.py +++ b/xsdata/utils/collections.py @@ -1,15 +1,9 @@ from collections import defaultdict +from collections.abc import Generator, Iterable, Iterator, Sequence from typing import ( Any, Callable, - Dict, - Generator, - Iterable, - Iterator, - List, Optional, - Sequence, - Set, TypeVar, ) @@ -24,7 +18,7 @@ def is_array(value: Any) -> bool: return isinstance(value, (list, set, frozenset, Generator)) -def unique_sequence(items: Iterable[T], key: Optional[str] = None) -> List[T]: +def unique_sequence(items: Iterable[T], key: Optional[str] = None) -> list[T]: """Return a new unique list, preserving the original order. Args: @@ -49,12 +43,12 @@ def is_new(val: Any) -> bool: return [item for item in items if is_new(item)] -def remove(items: Iterable[T], predicate: Callable) -> List[T]: +def remove(items: Iterable[T], predicate: Callable) -> list[T]: """Return a new list without the items that match the predicate.""" return [x for x in items if not predicate(x)] -def group_by(items: Iterable[T], key: Callable) -> Dict[Any, List[T]]: +def group_by(items: Iterable[T], key: Callable) -> dict[Any, list[T]]: """Group the items of an iterable object by the result of the callable.""" result = defaultdict(list) for item in items: @@ -89,19 +83,19 @@ def first(items: Iterator[T]) -> Optional[T]: return next(items, None) -def prepend(target: List, *args: Any): +def prepend(target: list, *args: Any): """Prepend items to the target list.""" target[:0] = args -def connected_components(lists: List[List[Any]]) -> Iterator[List[Any]]: +def connected_components(lists: list[list[Any]]) -> Iterator[list[Any]]: """Merge lists of lists that share common elements.""" neighbors = defaultdict(set) for each in lists: for item in each: neighbors[item].update(each) - def component(node: Any, neigh: Dict[Any, Set], see: Set[Any]): + def component(node: Any, neigh: dict[Any, set], see: set[Any]): nodes = {node} while nodes: next_node = nodes.pop() @@ -109,13 +103,13 @@ def component(node: Any, neigh: Dict[Any, Set], see: Set[Any]): nodes |= neigh[next_node] - see yield next_node - seen: Set[Any] = set() + seen: set[Any] = set() for item in neighbors: if item not in seen: yield sorted(component(item, neighbors, seen)) -def find_connected_component(groups: List[List[Any]], value: Any) -> int: +def find_connected_component(groups: list[list[Any]], value: Any) -> int: """Find the list index that contains the given value.""" for index, group in enumerate(groups): if value in group: diff --git a/xsdata/utils/constants.py b/xsdata/utils/constants.py index b24650761..c295b17bf 100644 --- a/xsdata/utils/constants.py +++ b/xsdata/utils/constants.py @@ -1,9 +1,10 @@ import sys -from typing import Any, Dict, Sequence, Tuple +from collections.abc import Sequence +from typing import Any -EMPTY_MAP: Dict = {} +EMPTY_MAP: dict = {} EMPTY_SEQUENCE: Sequence = [] -EMPTY_TUPLE: Tuple = () +EMPTY_TUPLE: tuple = () XML_FALSE = sys.intern("false") XML_TRUE = sys.intern("true") diff --git a/xsdata/utils/dates.py b/xsdata/utils/dates.py index 3f6fbe611..c048ec85b 100644 --- a/xsdata/utils/dates.py +++ b/xsdata/utils/dates.py @@ -1,6 +1,7 @@ import datetime from calendar import isleap -from typing import Any, Iterator, Optional, Union +from collections.abc import Iterator +from typing import Any, Optional, Union def parse_date_args(value: Any, fmt: str) -> Iterator[int]: diff --git a/xsdata/utils/downloader.py b/xsdata/utils/downloader.py index 588472cce..1b8f03e38 100644 --- a/xsdata/utils/downloader.py +++ b/xsdata/utils/downloader.py @@ -1,7 +1,7 @@ import os import re from pathlib import Path -from typing import Dict, Optional, Union +from typing import Optional, Union from xsdata.codegen import opener from xsdata.codegen.parsers import DefinitionsParser, SchemaParser @@ -24,12 +24,12 @@ class Downloader: downloaded: A cache of the downloaded resources """ - __slots__ = ("output", "base_path", "downloaded") + __slots__ = ("base_path", "downloaded", "output") def __init__(self, output: Path): self.output = output self.base_path: Optional[Path] = None - self.downloaded: Dict = {} + self.downloaded: dict = {} def wget(self, uri: str, location: Optional[str] = None): """Download handler for any uri input with circular protection.""" diff --git a/xsdata/utils/graphs.py b/xsdata/utils/graphs.py index 5d4c86065..d35a61bf3 100644 --- a/xsdata/utils/graphs.py +++ b/xsdata/utils/graphs.py @@ -1,7 +1,7 @@ -from typing import Dict, Iterator, List, Set +from collections.abc import Iterator -def strongly_connected_components(edges: Dict[str, List[str]]) -> Iterator[Set[str]]: +def strongly_connected_components(edges: dict[str, list[str]]) -> Iterator[set[str]]: """Compute Strongly Connected Components of a directed graph. From https://code.activestate.com/recipes/578507/ From @@ -13,12 +13,12 @@ def strongly_connected_components(edges: Dict[str, List[str]]) -> Iterator[Set[s Yields: A set of the strongly connected components """ - identified: Set[str] = set() - stack: List[str] = [] - index: Dict[str, int] = {} - boundaries: List[int] = [] + identified: set[str] = set() + stack: list[str] = [] + index: dict[str, int] = {} + boundaries: list[int] = [] - def dfs(v: str) -> Iterator[Set[str]]: + def dfs(v: str) -> Iterator[set[str]]: index[v] = len(stack) stack.append(v) boundaries.append(index[v]) diff --git a/xsdata/utils/namespaces.py b/xsdata/utils/namespaces.py index aad90a252..4f08f51a7 100644 --- a/xsdata/utils/namespaces.py +++ b/xsdata/utils/namespaces.py @@ -1,6 +1,6 @@ import functools import re -from typing import Dict, Optional, Tuple +from typing import Optional from xsdata.models.enums import Namespace from xsdata.utils import text @@ -14,7 +14,7 @@ ) -def load_prefix(uri: str, ns_map: Dict) -> Optional[str]: +def load_prefix(uri: str, ns_map: dict) -> Optional[str]: """Get or create a prefix for the uri in the prefix-URI map.""" for prefix, ns in ns_map.items(): if ns == uri: @@ -23,7 +23,7 @@ def load_prefix(uri: str, ns_map: Dict) -> Optional[str]: return generate_prefix(uri, ns_map) -def generate_prefix(uri: str, ns_map: Dict) -> str: +def generate_prefix(uri: str, ns_map: dict) -> str: """Generate a prefix for the given uri and append it in the prefix-URI map.""" namespace = Namespace.get_enum(uri) if namespace: @@ -37,17 +37,17 @@ def generate_prefix(uri: str, ns_map: Dict) -> str: return prefix -def prefix_exists(uri: str, ns_map: Dict) -> bool: +def prefix_exists(uri: str, ns_map: dict) -> bool: """Check if the uri exists in the prefix-URI namespace mapping.""" return uri in ns_map.values() -def is_default(uri: str, ns_map: Dict) -> bool: +def is_default(uri: str, ns_map: dict) -> bool: """Check if the uri exists and it has no prefix.""" return any(uri == ns and not prefix for prefix, ns in ns_map.items()) -def clean_prefixes(ns_map: Dict) -> Dict: +def clean_prefixes(ns_map: dict) -> dict: """Remove default namespace if it's also assigned to a prefix.""" result = {} for prefix, ns in ns_map.items(): @@ -91,7 +91,7 @@ def build_qname(tag_or_uri: Optional[str], tag: Optional[str] = None) -> str: @functools.lru_cache(maxsize=50) -def split_qname(qname: str) -> Tuple: +def split_qname(qname: str) -> tuple: """Split namespace qualified strings.""" if qname[0] == "{": left, right = text.split(qname[1:], "}") diff --git a/xsdata/utils/testing.py b/xsdata/utils/testing.py index ea9394b7c..d089ee26d 100644 --- a/xsdata/utils/testing.py +++ b/xsdata/utils/testing.py @@ -3,9 +3,10 @@ import importlib import random import unittest +from collections.abc import Sequence from contextlib import suppress from dataclasses import is_dataclass -from typing import Any, Callable, Dict, List, Optional, Sequence, Type, TypeVar +from typing import Any, Callable, Optional, TypeVar from xsdata.codegen.models import ( Attr, @@ -82,7 +83,7 @@ def setUp(self): class Factory(abc.ABC): counter = 0 - model: Type + model: type @classmethod @abc.abstractmethod @@ -99,7 +100,7 @@ def next_letter(cls) -> str: return chr(cls.counter) @classmethod - def list(cls, number: int, **kwargs: Any) -> List: + def list(cls, number: int, **kwargs: Any) -> list: return [cls.create(**kwargs) for _ in range(number)] @@ -118,11 +119,11 @@ def create( abstract: bool = False, mixed: bool = False, nillable: bool = False, - extensions: Optional[List[Extension]] = None, - substitutions: Optional[List[str]] = None, - attrs: Optional[List[Attr]] = None, - inner: Optional[List[Class]] = None, - ns_map: Optional[Dict] = None, + extensions: Optional[list[Extension]] = None, + substitutions: Optional[list[str]] = None, + attrs: Optional[list[Attr]] = None, + inner: Optional[list[Class]] = None, + ns_map: Optional[dict] = None, location: str = "tests.xsd", package: Optional[str] = None, module: Optional[str] = "tests", @@ -269,8 +270,8 @@ def create( cls, name: Optional[str] = None, index: Optional[int] = None, - types: Optional[List[AttrType]] = None, - choices: Optional[List[Attr]] = None, + types: Optional[list[AttrType]] = None, + choices: Optional[list[Attr]] = None, tag: Optional[str] = None, namespace: Optional[str] = None, wrapper: Optional[str] = None, @@ -388,8 +389,8 @@ def create( local_name: Optional[str] = None, wrapper: Optional[str] = None, index: int = 0, - types: Optional[Sequence[Type]] = None, - clazz: Optional[Type] = None, + types: Optional[Sequence[type]] = None, + clazz: Optional[type] = None, init: bool = True, mixed: bool = False, factory: Optional[Callable] = None, @@ -403,7 +404,7 @@ def create( default: Optional[Any] = None, xml_type: str = XmlType.ELEMENT, namespaces: Optional[Sequence[str]] = None, - elements: Optional[Dict[str, XmlVar]] = None, + elements: Optional[dict[str, XmlVar]] = None, wildcards: Optional[Sequence[XmlVar]] = None, prefix: str = "field_", **kwargs: Any, @@ -454,15 +455,15 @@ class XmlMetaFactory(Factory): @classmethod def create( # type: ignore cls, - clazz: Type, + clazz: type, qname: Optional[str] = None, target_qname: Optional[str] = None, nillable: bool = False, text: Optional[XmlVar] = None, choices: Optional[Sequence[XmlVar]] = None, - elements: Optional[Dict[str, Sequence[XmlVar]]] = None, + elements: Optional[dict[str, Sequence[XmlVar]]] = None, wildcards: Optional[Sequence[XmlVar]] = None, - attributes: Optional[Dict[str, XmlVar]] = None, + attributes: Optional[dict[str, XmlVar]] = None, any_attributes: Optional[Sequence[XmlVar]] = None, **kwargs: Any, ) -> XmlMeta: @@ -513,7 +514,7 @@ def create( type: Optional[DtdAttributeType] = None, default: Optional[DtdAttributeDefault] = None, default_value: Optional[str] = None, - values: Optional[List[str]] = None, + values: Optional[list[str]] = None, **kwargs: Any, ) -> DtdAttribute: if name is None: @@ -579,8 +580,8 @@ def create( prefix: Optional[str] = None, type: Optional[DtdElementType] = None, content: Optional[DtdContent] = None, - attributes: Optional[List[DtdAttribute]] = None, - ns_map: Optional[Dict] = None, + attributes: Optional[list[DtdAttribute]] = None, + ns_map: Optional[dict] = None, **kwargs: Any, ) -> DtdElement: if name is None: @@ -609,7 +610,7 @@ class DtdFactory(Factory): @classmethod def create( cls, - elements: Optional[List[DtdElement]] = None, + elements: Optional[list[DtdElement]] = None, location: Optional[str] = None, **kwargs: Any, ) -> Dtd: