elementpath 4.8.0__tar.gz → 5.0.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. {elementpath-4.8.0 → elementpath-5.0.0}/CHANGELOG.rst +10 -0
  2. {elementpath-4.8.0 → elementpath-5.0.0}/MANIFEST.in +1 -4
  3. {elementpath-4.8.0 → elementpath-5.0.0}/PKG-INFO +18 -27
  4. {elementpath-4.8.0 → elementpath-5.0.0}/README.rst +1 -1
  5. {elementpath-4.8.0 → elementpath-5.0.0}/doc/conf.py +2 -2
  6. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/__init__.py +1 -1
  7. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/aliases.py +8 -8
  8. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/collations.py +4 -4
  9. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/compare.py +1 -1
  10. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/__init__.py +6 -15
  11. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/atomic_types.py +32 -33
  12. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/binary.py +1 -2
  13. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/datetime.py +9 -9
  14. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/numeric.py +2 -2
  15. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/proxies.py +2 -2
  16. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/untyped.py +2 -2
  17. elementpath-5.0.0/elementpath/decoder.py +167 -0
  18. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/etree.py +46 -81
  19. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/exceptions.py +10 -2
  20. elementpath-5.0.0/elementpath/extras/pathnodes.py +262 -0
  21. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/helpers.py +20 -12
  22. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/namespaces.py +58 -2
  23. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/protocols.py +9 -9
  24. elementpath-5.0.0/elementpath/regex/categories_fallback.py +77 -0
  25. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/character_classes.py +3 -3
  26. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/codepoints.py +4 -5
  27. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/unicode_subsets.py +22 -13
  28. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/schema_proxy.py +4 -4
  29. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/sequence_types.py +3 -5
  30. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/serialization.py +7 -7
  31. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/tdop.py +33 -35
  32. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/tree_builders.py +56 -91
  33. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath1/_xpath1_axes.py +1 -1
  34. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath1/_xpath1_functions.py +3 -3
  35. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath1/_xpath1_operators.py +17 -17
  36. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath1/xpath1_parser.py +26 -30
  37. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath2/_xpath2_constructors.py +5 -8
  38. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath2/_xpath2_functions.py +22 -51
  39. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath2/_xpath2_operators.py +14 -14
  40. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath2/xpath2_parser.py +18 -18
  41. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/_xpath30_functions.py +25 -37
  42. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/_xpath30_operators.py +5 -5
  43. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/xpath30_helpers.py +6 -6
  44. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/xpath30_parser.py +4 -4
  45. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath31/_xpath31_functions.py +13 -13
  46. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath31/_xpath31_operators.py +1 -1
  47. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath31/xpath31_parser.py +3 -3
  48. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath_context.py +19 -31
  49. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath_nodes.py +147 -133
  50. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath_selectors.py +5 -5
  51. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath_tokens.py +28 -30
  52. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath.egg-info/PKG-INFO +18 -27
  53. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath.egg-info/SOURCES.txt +9 -7
  54. elementpath-5.0.0/elementpath.egg-info/requires.txt +16 -0
  55. elementpath-5.0.0/pyproject.toml +87 -0
  56. {elementpath-4.8.0 → elementpath-5.0.0}/requirements-dev.txt +4 -4
  57. elementpath-5.0.0/tests/__init__.py +0 -0
  58. {elementpath-4.8.0 → elementpath-5.0.0}/tests/memory_profiling.py +27 -3
  59. elementpath-4.8.0/tests/test_typing.py → elementpath-5.0.0/tests/run_typing_tests.py +1 -1
  60. elementpath-4.8.0/tests/execute_w3c_tests.py → elementpath-5.0.0/tests/run_w3c_tests.py +1 -0
  61. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_datatypes.py +7 -7
  62. elementpath-5.0.0/tests/test_decoder.py +61 -0
  63. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_etree.py +77 -154
  64. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_helpers.py +177 -0
  65. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_namespaces.py +44 -3
  66. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_package.py +6 -6
  67. elementpath-5.0.0/tests/test_pathnodes.py +63 -0
  68. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_tree_builders.py +3 -3
  69. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_validators.py +1 -1
  70. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath1_parser.py +2 -2
  71. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath2_constructors.py +3 -0
  72. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath2_functions.py +13 -18
  73. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath2_parser.py +15 -10
  74. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath_context.py +1 -0
  75. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath_nodes.py +10 -8
  76. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath_tokens.py +1 -0
  77. {elementpath-4.8.0 → elementpath-5.0.0}/tox.ini +44 -41
  78. elementpath-4.8.0/.coveragerc +0 -12
  79. elementpath-4.8.0/elementpath/_typing.py +0 -27
  80. elementpath-4.8.0/elementpath/decoder.py +0 -170
  81. elementpath-4.8.0/elementpath.egg-info/requires.txt +0 -12
  82. elementpath-4.8.0/mypy.ini +0 -2
  83. elementpath-4.8.0/setup.py +0 -59
  84. {elementpath-4.8.0 → elementpath-5.0.0}/LICENSE +0 -0
  85. {elementpath-4.8.0 → elementpath-5.0.0}/doc/Makefile +0 -0
  86. {elementpath-4.8.0 → elementpath-5.0.0}/doc/advanced.rst +0 -0
  87. {elementpath-4.8.0 → elementpath-5.0.0}/doc/index.rst +0 -0
  88. {elementpath-4.8.0 → elementpath-5.0.0}/doc/introduction.rst +0 -0
  89. {elementpath-4.8.0 → elementpath-5.0.0}/doc/make.bat +0 -0
  90. {elementpath-4.8.0 → elementpath-5.0.0}/doc/pratt_api.rst +0 -0
  91. {elementpath-4.8.0 → elementpath-5.0.0}/doc/requirements.txt +0 -0
  92. {elementpath-4.8.0 → elementpath-5.0.0}/doc/xpath_api.rst +0 -0
  93. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/qname.py +0 -0
  94. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/string.py +0 -0
  95. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/datatypes/uri.py +0 -0
  96. {elementpath-4.8.0/tests → elementpath-5.0.0/elementpath/extras}/__init__.py +0 -0
  97. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/py.typed +0 -0
  98. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/__init__.py +0 -0
  99. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/patterns.py +0 -0
  100. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/unicode_blocks.py +0 -0
  101. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/regex/unicode_categories.py +0 -0
  102. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/validators/__init__.py +0 -0
  103. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/validators/analyze-string.xsd +0 -0
  104. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/validators/schema-for-json.xsd +0 -0
  105. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath1/__init__.py +0 -0
  106. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath2/__init__.py +0 -0
  107. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath3.py +0 -0
  108. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/__init__.py +0 -0
  109. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath30/_translation_maps.py +0 -0
  110. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath/xpath31/__init__.py +0 -0
  111. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath.egg-info/dependency_links.txt +0 -0
  112. {elementpath-4.8.0 → elementpath-5.0.0}/elementpath.egg-info/top_level.txt +0 -0
  113. {elementpath-4.8.0 → elementpath-5.0.0}/scripts/generate_codepoints.py +0 -0
  114. {elementpath-4.8.0 → elementpath-5.0.0}/setup.cfg +0 -0
  115. {elementpath-4.8.0 → elementpath-5.0.0}/tests/mypy_tests/advanced.py +0 -0
  116. {elementpath-4.8.0 → elementpath-5.0.0}/tests/mypy_tests/protocols.py +0 -0
  117. {elementpath-4.8.0 → elementpath-5.0.0}/tests/mypy_tests/selectors.py +0 -0
  118. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/analyze-string.xsd +0 -0
  119. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/external_entity.xml +0 -0
  120. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/sample.xml +0 -0
  121. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/schema-for-json.xsd +0 -0
  122. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/unparsed_entity.xml +0 -0
  123. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/unused_external_entity.xml +0 -0
  124. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/unused_unparsed_entity.xml +0 -0
  125. {elementpath-4.8.0 → elementpath-5.0.0}/tests/resources/with_entity.xml +0 -0
  126. /elementpath-4.8.0/tests/test_elementpath.py → /elementpath-5.0.0/tests/run_all_tests.py +0 -0
  127. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_collations.py +0 -0
  128. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_compare.py +0 -0
  129. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_exceptions.py +0 -0
  130. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_regex.py +0 -0
  131. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_schema_context.py +0 -0
  132. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_schema_proxy.py +0 -0
  133. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_selectors.py +0 -0
  134. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_sequence_types.py +0 -0
  135. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_serialization.py +0 -0
  136. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_tdop_parser.py +0 -0
  137. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath30.py +0 -0
  138. {elementpath-4.8.0 → elementpath-5.0.0}/tests/test_xpath31.py +0 -0
  139. {elementpath-4.8.0 → elementpath-5.0.0}/tests/xpath_test_class.py +0 -0
@@ -2,6 +2,15 @@
2
2
  CHANGELOG
3
3
  *********
4
4
 
5
+ `v5.0.0`_ (2025-04-27)
6
+ ======================
7
+ * Replace SafeXMLParser with SafeExpatParser
8
+ * Drop compatibility with Python 3.8
9
+ * Restruct node trees with XPathNodeTree backbone
10
+ * Unicode categories fallback with a warning (issue #85)
11
+ * Rewriting decoder module (issue #87)
12
+ * Add extras subpackage for experiment XDM and XPath on Path objects
13
+
5
14
  `v4.8.0`_ (2025-03-03)
6
15
  ======================
7
16
  * Add full PSVI type labeling in XDM to solve type errors with XSD 1.1 assertions
@@ -492,3 +501,4 @@ CHANGELOG
492
501
  .. _v4.6.0: https://github.com/sissaschool/elementpath/compare/v4.5.0...v4.6.0
493
502
  .. _v4.7.0: https://github.com/sissaschool/elementpath/compare/v4.6.0...v4.7.0
494
503
  .. _v4.8.0: https://github.com/sissaschool/elementpath/compare/v4.7.0...v4.8.0
504
+ .. _v5.0.0: https://github.com/sissaschool/elementpath/compare/v4.8.0...v5.0.0
@@ -2,12 +2,9 @@ include LICENSE
2
2
  include MANIFEST.in
3
3
  include README.rst
4
4
  include CHANGELOG.rst
5
- include setup.py
6
- include setup.cfg
5
+ include pyproject.toml
7
6
  include requirements-dev.txt
8
7
  include tox.ini
9
- include .coveragerc
10
- include mypy.ini
11
8
  include doc/*
12
9
 
13
10
  recursive-include elementpath *
@@ -1,22 +1,18 @@
1
- Metadata-Version: 2.2
1
+ Metadata-Version: 2.4
2
2
  Name: elementpath
3
- Version: 4.8.0
3
+ Version: 5.0.0
4
4
  Summary: XPath 1.0/2.0/3.0/3.1 parsers and selectors for ElementTree and lxml
5
- Home-page: https://github.com/sissaschool/elementpath
6
- Author: Davide Brunato
7
- Author-email: brunato@sissa.it
8
- License: MIT
9
- Keywords: XPath,XPath2,XPath3,XPath31,Pratt-parser,ElementTree,lxml
5
+ Author-email: Davide Brunato <brunato@sissa.it>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/sissaschool/elementpath
10
8
  Classifier: Development Status :: 5 - Production/Stable
11
9
  Classifier: Intended Audience :: Developers
12
10
  Classifier: Intended Audience :: Information Technology
13
11
  Classifier: Intended Audience :: Science/Research
14
- Classifier: License :: OSI Approved :: MIT License
15
12
  Classifier: Operating System :: OS Independent
16
13
  Classifier: Programming Language :: Python
17
14
  Classifier: Programming Language :: Python :: 3
18
15
  Classifier: Programming Language :: Python :: 3 :: Only
19
- Classifier: Programming Language :: Python :: 3.8
20
16
  Classifier: Programming Language :: Python :: 3.9
21
17
  Classifier: Programming Language :: Python :: 3.10
22
18
  Classifier: Programming Language :: Python :: 3.11
@@ -27,29 +23,24 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
27
23
  Classifier: Programming Language :: Python :: Implementation :: PyPy
28
24
  Classifier: Topic :: Software Development :: Libraries
29
25
  Classifier: Topic :: Text Processing :: Markup :: XML
30
- Requires-Python: >=3.8
26
+ Requires-Python: >=3.9
27
+ Description-Content-Type: text/x-rst
31
28
  License-File: LICENSE
32
29
  Provides-Extra: dev
33
- Requires-Dist: tox; extra == "dev"
34
30
  Requires-Dist: coverage; extra == "dev"
31
+ Requires-Dist: flake8; extra == "dev"
35
32
  Requires-Dist: lxml; extra == "dev"
36
- Requires-Dist: xmlschema>=3.3.2; extra == "dev"
37
- Requires-Dist: Sphinx; extra == "dev"
38
- Requires-Dist: memory-profiler; extra == "dev"
33
+ Requires-Dist: lxml-stubs; extra == "dev"
39
34
  Requires-Dist: memray; extra == "dev"
40
- Requires-Dist: flake8; extra == "dev"
41
35
  Requires-Dist: mypy; extra == "dev"
42
- Requires-Dist: lxml-stubs; extra == "dev"
43
- Dynamic: author
44
- Dynamic: author-email
45
- Dynamic: classifier
46
- Dynamic: description
47
- Dynamic: home-page
48
- Dynamic: keywords
49
- Dynamic: license
50
- Dynamic: provides-extra
51
- Dynamic: requires-python
52
- Dynamic: summary
36
+ Requires-Dist: psutil; extra == "dev"
37
+ Requires-Dist: sphinx; extra == "dev"
38
+ Requires-Dist: tox; extra == "dev"
39
+ Requires-Dist: xmlschema>=4.0.1; extra == "dev"
40
+ Provides-Extra: docs
41
+ Requires-Dist: sphinx; extra == "docs"
42
+ Requires-Dist: readthedocs-sphinx-search; extra == "docs"
43
+ Dynamic: license-file
53
44
 
54
45
  ***********
55
46
  elementpath
@@ -81,7 +72,7 @@ has it's own implementation of XPath 1.0.
81
72
  Installation and usage
82
73
  ======================
83
74
 
84
- You can install the package with *pip* in a Python 3.8+ environment::
75
+ You can install the package with *pip* in a Python 3.9+ environment::
85
76
 
86
77
  pip install elementpath
87
78
 
@@ -28,7 +28,7 @@ has it's own implementation of XPath 1.0.
28
28
  Installation and usage
29
29
  ======================
30
30
 
31
- You can install the package with *pip* in a Python 3.8+ environment::
31
+ You can install the package with *pip* in a Python 3.9+ environment::
32
32
 
33
33
  pip install elementpath
34
34
 
@@ -29,9 +29,9 @@ copyright = '2018-2025, SISSA (International School for Advanced Studies)'
29
29
  author = 'Davide Brunato'
30
30
 
31
31
  # The short X.Y version
32
- version = '4.8'
32
+ version = '5.0'
33
33
  # The full version, including alpha/beta/rc tags
34
- release = '4.8.0'
34
+ release = '5.0.0'
35
35
 
36
36
  # -- General configuration ---------------------------------------------------
37
37
 
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # @author Davide Brunato <brunato@sissa.it>
9
9
  #
10
- __version__ = '4.8.0'
10
+ __version__ = '5.0.0'
11
11
  __author__ = "Davide Brunato"
12
12
  __contact__ = "brunato@sissa.it"
13
13
  __copyright__ = "Copyright 2018-2025, SISSA"
@@ -10,23 +10,23 @@
10
10
  """
11
11
  Common type hints aliases for elementpath.
12
12
  """
13
- from typing import Any, List, Optional, NoReturn, Tuple, Type, TYPE_CHECKING, TypeVar, Union
13
+ from typing import Any, Optional, NoReturn, TYPE_CHECKING, TypeVar, Union
14
14
 
15
- from elementpath._typing import MutableMapping
15
+ from collections.abc import MutableMapping
16
16
 
17
17
  ##
18
- # Type aliases
18
+ # type aliases
19
19
  NamespacesType = MutableMapping[str, str]
20
20
  NsmapType = MutableMapping[Optional[str], str] # compatible with the nsmap of lxml Element
21
21
  AnyNsmapType = Union[NamespacesType, NsmapType, None] # for composition and function arguments
22
22
 
23
- NargsType = Optional[Union[int, Tuple[int, Optional[int]]]]
24
- ClassCheckType = Union[Type[Any], Tuple[Type[Any], ...]]
23
+ NargsType = Optional[Union[int, tuple[int, Optional[int]]]]
24
+ ClassCheckType = Union[type[Any], tuple[type[Any], ...]]
25
25
 
26
26
  T = TypeVar('T')
27
- Emptiable = Union[T, List[NoReturn]]
28
- SequenceType = Union[T, List[T]]
29
- InputType = Union[None, T, List[T], Tuple[T, ...]]
27
+ Emptiable = Union[T, list[NoReturn]]
28
+ SequenceType = Union[T, list[T]]
29
+ InputType = Union[None, T, list[T], tuple[T, ...]]
30
30
 
31
31
  if TYPE_CHECKING:
32
32
  from elementpath.datatypes import AtomicType, ArithmeticType, NumericType
@@ -11,7 +11,7 @@ import locale
11
11
  import threading
12
12
  from contextlib import AbstractContextManager
13
13
  from types import TracebackType
14
- from typing import TYPE_CHECKING, Any, Optional, Tuple, Type, Union
14
+ from typing import TYPE_CHECKING, Any, Optional, Union
15
15
  from urllib.parse import urljoin, urlsplit
16
16
 
17
17
  from elementpath.exceptions import xpath_error
@@ -76,9 +76,9 @@ class CollationManager(context_class_base):
76
76
  """
77
77
  Context Manager for collations. Provide helper operators as methods.
78
78
  """
79
- lc_collate: Union[None, str, Tuple[Optional[str], Optional[str]]]
79
+ lc_collate: Union[None, str, tuple[Optional[str], Optional[str]]]
80
80
  fallback: bool = False
81
- _current_lc_collate: Optional[Tuple[Optional[str], Optional[str]]] = None
81
+ _current_lc_collate: Optional[tuple[Optional[str], Optional[str]]] = None
82
82
 
83
83
  def __init__(self,
84
84
  collation: Optional[str],
@@ -149,7 +149,7 @@ class CollationManager(context_class_base):
149
149
 
150
150
  return self
151
151
 
152
- def __exit__(self, exc_type: Optional[Type[BaseException]],
152
+ def __exit__(self, exc_type: Optional[type[BaseException]],
153
153
  exc_val: Optional[BaseException],
154
154
  exc_tb: Optional[TracebackType]) -> None:
155
155
  if self._current_lc_collate is not None:
@@ -13,7 +13,7 @@ from functools import cmp_to_key
13
13
  from itertools import zip_longest
14
14
  from typing import Any, Optional
15
15
 
16
- from elementpath._typing import Callable, Iterable, Iterator
16
+ from collections.abc import Callable, Iterable, Iterator
17
17
  from elementpath.protocols import ElementProtocol
18
18
  from elementpath.exceptions import xpath_error
19
19
  from elementpath.datatypes import UntypedAtomic, AnyURI, AbstractQName
@@ -1,5 +1,5 @@
1
1
  #
2
- # Copyright (c), 2018-2020, SISSA (International School for Advanced Studies).
2
+ # Copyright (c), 2018-2025, SISSA (International School for Advanced Studies).
3
3
  # All rights reserved.
4
4
  # This file is distributed under the terms of the MIT License.
5
5
  # See the file 'LICENSE' in the root directory of the present
@@ -15,8 +15,7 @@ exceptions in order to be reusable in other packages.
15
15
  from decimal import Decimal
16
16
  from typing import Union
17
17
 
18
- from .atomic_types import xsd10_atomic_types, xsd11_atomic_types, \
19
- AtomicTypeMeta, AnyAtomicType
18
+ from .atomic_types import xsd_atomic_types, AtomicTypeMeta, AnyAtomicType
20
19
  from .untyped import UntypedAtomic
21
20
  from .qname import AbstractQName, QName, Notation
22
21
  from .numeric import Float10, Float, Integer, Int, NegativeInteger, \
@@ -33,22 +32,15 @@ from .datetime import AbstractDateTime, DateTime10, DateTime, DateTimeStamp, \
33
32
  from .proxies import BooleanProxy, DecimalProxy, DoubleProxy10, DoubleProxy, \
34
33
  StringProxy, NumericProxy, ArithmeticProxy
35
34
 
36
-
37
- xsd11_atomic_types.update(
38
- (k, v) for k, v in xsd10_atomic_types.items() if k not in xsd11_atomic_types
39
- )
40
-
41
35
  ###
42
36
  # Aliases for type annotations
43
37
  AtomicType = Union[str, int, float, Decimal, bool, AnyAtomicType]
44
38
  NumericType = Union[int, float, Decimal]
45
39
  ArithmeticType = Union[NumericType, AbstractDateTime, Duration, UntypedAtomic]
46
- DatetimeValueType = AbstractDateTime # keep until v5.0 for backward compatibility
47
40
 
48
- __all__ = ['xsd10_atomic_types', 'xsd11_atomic_types',
49
- 'AtomicTypeMeta', 'AnyAtomicType', 'NumericProxy', 'ArithmeticProxy',
50
- 'AbstractDateTime', 'DateTime10', 'DateTime', 'DateTimeStamp', 'Date10',
51
- 'Date', 'Time', 'GregorianDay', 'GregorianMonth', 'GregorianMonthDay',
41
+ __all__ = ['xsd_atomic_types', 'AtomicTypeMeta', 'AnyAtomicType', 'NumericProxy',
42
+ 'ArithmeticProxy', 'AbstractDateTime', 'DateTime10', 'DateTime', 'DateTimeStamp',
43
+ 'Date10', 'Date', 'Time', 'GregorianDay', 'GregorianMonth', 'GregorianMonthDay',
52
44
  'GregorianYear10', 'GregorianYear', 'GregorianYearMonth10', 'GregorianYearMonth',
53
45
  'Timezone', 'Duration', 'YearMonthDuration', 'DayTimeDuration', 'StringProxy',
54
46
  'NormalizedString', 'XsdToken', 'Language', 'Name', 'NCName', 'Id', 'Idref',
@@ -57,5 +49,4 @@ __all__ = ['xsd10_atomic_types', 'xsd11_atomic_types',
57
49
  'Byte', 'NonNegativeInteger', 'PositiveInteger', 'UnsignedLong', 'UnsignedInt',
58
50
  'UnsignedShort', 'UnsignedByte', 'AnyURI', 'Notation', 'QName', 'BooleanProxy',
59
51
  'DecimalProxy', 'DoubleProxy10', 'DoubleProxy', 'UntypedAtomic', 'AbstractBinary',
60
- 'AtomicType', 'DatetimeValueType', 'OrderedDateTime', 'AbstractQName',
61
- 'NumericType', 'ArithmeticType']
52
+ 'AtomicType', 'OrderedDateTime', 'AbstractQName', 'NumericType', 'ArithmeticType']
@@ -8,11 +8,10 @@
8
8
  # @author Davide Brunato <brunato@sissa.it>
9
9
  #
10
10
  from abc import ABCMeta, abstractmethod
11
- from typing import Any, Dict, Optional, Tuple, Type
11
+ from types import MappingProxyType
12
+ from typing import Any, Optional
12
13
  import re
13
14
 
14
- from elementpath._typing import Pattern
15
-
16
15
  XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
17
16
 
18
17
  ###
@@ -21,11 +20,16 @@ XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
21
20
  # into a dictionary. Some classes of XSD primitive types are defined
22
21
  # as proxies of basic Python datatypes.
23
22
 
24
- xsd10_atomic_types: Dict[Optional[str], 'AtomicTypeMeta'] = {}
25
- """Dictionary of builtin XSD 1.0 atomic types."""
23
+ _xsd_atomic_types: dict[str, dict[Optional[str], 'AtomicTypeMeta']] = {
24
+ '1.0': {},
25
+ '1.1': {}
26
+ }
27
+ """Registry of builtin XSD 1.0/1.1 atomic types."""
26
28
 
27
- xsd11_atomic_types: Dict[Optional[str], 'AtomicTypeMeta'] = {}
28
- """Dictionary of builtin XSD 1.1 atomic types."""
29
+ xsd_atomic_types = MappingProxyType({
30
+ '1.0': MappingProxyType(_xsd_atomic_types['1.0']),
31
+ '1.1': MappingProxyType(_xsd_atomic_types['1.1']),
32
+ })
29
33
 
30
34
 
31
35
  class AtomicTypeMeta(ABCMeta):
@@ -36,10 +40,8 @@ class AtomicTypeMeta(ABCMeta):
36
40
  of XSD atomic types and also the expanded name is added.
37
41
  """
38
42
  xsd_version: str
39
- pattern: Pattern[str]
40
- name: Optional[str] = None
41
43
 
42
- def __new__(mcs, class_name: str, bases: Tuple[Type[Any], ...], dict_: Dict[str, Any]) \
44
+ def __new__(mcs, class_name: str, bases: tuple[type[Any], ...], dict_: dict[str, Any]) \
43
45
  -> 'AtomicTypeMeta':
44
46
  try:
45
47
  name = dict_['name']
@@ -49,28 +51,26 @@ class AtomicTypeMeta(ABCMeta):
49
51
  if name is not None and not isinstance(name, str):
50
52
  raise TypeError("attribute 'name' must be a string or None")
51
53
 
52
- dict_['is_valid'] = classmethod(mcs.is_valid)
53
- dict_['invalid_type'] = classmethod(mcs.invalid_type)
54
- dict_['invalid_value'] = classmethod(mcs.invalid_value)
55
54
  cls = super(AtomicTypeMeta, mcs).__new__(mcs, class_name, bases, dict_)
56
55
 
57
- # Add missing attributes and methods
58
- if not hasattr(cls, 'xsd_version'):
59
- cls.xsd_version = '1.0'
60
- if not hasattr(cls, 'pattern'):
61
- cls.pattern = re.compile(r'^$')
62
-
63
- # Register class with a name
56
+ # Register ony derived classes with a name
64
57
  if name:
65
- expanded_name = '{%s}%s' % (XSD_NAMESPACE, name)
66
- if cls.xsd_version == '1.0':
67
- xsd10_atomic_types[name] = xsd10_atomic_types[expanded_name] = cls
68
- else:
69
- xsd11_atomic_types[name] = xsd11_atomic_types[expanded_name] = cls
58
+ for xsd_version, atomic_types in _xsd_atomic_types.items():
59
+ if cls.xsd_version <= xsd_version and (
60
+ name not in atomic_types or atomic_types[name].xsd_version < cls.xsd_version
61
+ ):
62
+ atomic_types[name] = cls
70
63
 
71
64
  return cls
72
65
 
73
- def validate(cls: Type[Any], value: object) -> None:
66
+
67
+ class AnyAtomicType(metaclass=AtomicTypeMeta):
68
+ name: Optional[str] = 'anyAtomicType'
69
+ xsd_version: str = '1.0'
70
+ pattern: re.Pattern[str] = re.compile(r'^$')
71
+
72
+ @classmethod
73
+ def validate(cls, value: object) -> None:
74
74
  if isinstance(value, cls):
75
75
  return
76
76
  elif isinstance(value, str):
@@ -79,7 +79,8 @@ class AtomicTypeMeta(ABCMeta):
79
79
  else:
80
80
  raise cls.invalid_type(value)
81
81
 
82
- def is_valid(cls: Type[Any], value: object) -> bool:
82
+ @classmethod
83
+ def is_valid(cls, value: object) -> bool:
83
84
  try:
84
85
  cls.validate(value)
85
86
  except (TypeError, ValueError):
@@ -87,20 +88,18 @@ class AtomicTypeMeta(ABCMeta):
87
88
  else:
88
89
  return True
89
90
 
90
- def invalid_type(cls: Type[Any], value: object) -> TypeError:
91
+ @classmethod
92
+ def invalid_type(cls, value: object) -> TypeError:
91
93
  if cls.name:
92
94
  return TypeError('invalid type {!r} for xs:{}'.format(type(value), cls.name))
93
95
  return TypeError('invalid type {!r} for {!r}'.format(type(value), cls))
94
96
 
95
- def invalid_value(cls: Type[Any], value: object) -> ValueError:
97
+ @classmethod
98
+ def invalid_value(cls, value: object) -> ValueError:
96
99
  if cls.name:
97
100
  return ValueError('invalid value {!r} for xs:{}'.format(value, cls.name))
98
101
  return ValueError('invalid value {!r} for {!r}'.format(value, cls))
99
102
 
100
-
101
- class AnyAtomicType(metaclass=AtomicTypeMeta):
102
- name = 'anyAtomicType'
103
-
104
103
  @abstractmethod
105
104
  def __init__(self, value: Any) -> None:
106
105
  raise NotImplementedError()
@@ -9,7 +9,7 @@
9
9
  #
10
10
  import re
11
11
  from abc import abstractmethod
12
- from typing import Any, Callable, Union
12
+ from typing import Union
13
13
  import codecs
14
14
 
15
15
  from elementpath.helpers import collapse_white_spaces
@@ -25,7 +25,6 @@ class AbstractBinary(AnyAtomicType):
25
25
  :param ordered: a boolean that enable total ordering for the instance, `False` for default.
26
26
  """
27
27
  value: bytes
28
- invalid_type: Callable[[Any], TypeError]
29
28
 
30
29
  def __init__(self, value: Union[str, bytes, UntypedAtomic, 'AbstractBinary'],
31
30
  ordered: bool = False) -> None:
@@ -8,15 +8,15 @@
8
8
  # @author Davide Brunato <brunato@sissa.it>
9
9
  #
10
10
  from abc import abstractmethod
11
+ from collections.abc import Callable
11
12
  import re
12
13
  import math
13
14
  import operator
14
15
  import datetime
15
16
  from calendar import isleap
16
17
  from decimal import Decimal, Context
17
- from typing import cast, Any, Dict, Optional, Tuple, Type, TypeVar, Union
18
+ from typing import cast, Any, Optional, TypeVar, Union
18
19
 
19
- from elementpath._typing import Callable
20
20
  from elementpath.helpers import MONTH_DAYS_LEAP, MONTH_DAYS, DAYS_IN_4Y, \
21
21
  DAYS_IN_100Y, DAYS_IN_400Y, days_from_common_era, adjust_day, \
22
22
  normalized_seconds, months2days, round_number
@@ -63,7 +63,7 @@ class Timezone(datetime.tzinfo):
63
63
  raise ValueError("{!r} has not an integral number of minutes".format(duration))
64
64
  return cls(datetime.timedelta(seconds=int(duration.seconds)))
65
65
 
66
- def __getinitargs__(self) -> Tuple[datetime.timedelta]:
66
+ def __getinitargs__(self) -> tuple[datetime.timedelta]:
67
67
  return self.offset,
68
68
 
69
69
  def __hash__(self) -> int:
@@ -267,11 +267,11 @@ class AbstractDateTime(AnyAtomicType):
267
267
  def astimezone(self, tz: Optional[datetime.tzinfo] = None) -> datetime.datetime:
268
268
  return self._dt.astimezone(tz)
269
269
 
270
- def isocalendar(self) -> Tuple[int, int, int]:
270
+ def isocalendar(self) -> tuple[int, int, int]:
271
271
  return self._dt.isocalendar()
272
272
 
273
273
  @classmethod
274
- def fromstring(cls: Type[_DT], datetime_string: str, tzinfo: Optional[Timezone] = None) \
274
+ def fromstring(cls: type[_DT], datetime_string: str, tzinfo: Optional[Timezone] = None) \
275
275
  -> _DT:
276
276
  """
277
277
  Creates an XSD date/time instance from a string formatted value.
@@ -293,7 +293,7 @@ class AbstractDateTime(AnyAtomicType):
293
293
  raise ValueError(msg.format(datetime_string, cls))
294
294
 
295
295
  match_dict = match.groupdict()
296
- kwargs: Dict[str, int] = {
296
+ kwargs: dict[str, int] = {
297
297
  k: int(v) for k, v in match_dict.items() if k != 'tzinfo' and v is not None
298
298
  }
299
299
 
@@ -322,7 +322,7 @@ class AbstractDateTime(AnyAtomicType):
322
322
  return cls(tzinfo=tzinfo, **kwargs)
323
323
 
324
324
  @classmethod
325
- def fromdatetime(cls: Type[_DT], dt: Union[datetime.datetime, datetime.date, datetime.time],
325
+ def fromdatetime(cls: type[_DT], dt: Union[datetime.datetime, datetime.date, datetime.time],
326
326
  year: Optional[int] = None) -> _DT:
327
327
  """
328
328
  Creates an XSD date/time instance from a datetime.datetime/date/time instance.
@@ -343,7 +343,7 @@ class AbstractDateTime(AnyAtomicType):
343
343
  return cls(**kwargs)
344
344
 
345
345
  # Python can't compare offset-naive and offset-aware datetimes
346
- def _get_operands(self, other: object) -> Tuple[datetime.datetime, datetime.datetime]:
346
+ def _get_operands(self, other: object) -> tuple[datetime.datetime, datetime.datetime]:
347
347
  if isinstance(other, (self.__class__, datetime.datetime)) or \
348
348
  isinstance(self, other.__class__):
349
349
  dt: datetime.datetime = getattr(other, '_dt', cast(datetime.datetime, other))
@@ -831,7 +831,7 @@ class Duration(AnyAtomicType):
831
831
  return value
832
832
 
833
833
  @classmethod
834
- def fromstring(cls: Type[_D], text: str) -> _D:
834
+ def fromstring(cls: type[_D], text: str) -> _D:
835
835
  """
836
836
  Creates a Duration instance from a formatted XSD duration string.
837
837
 
@@ -9,7 +9,7 @@
9
9
  #
10
10
  import math
11
11
  import re
12
- from typing import Any, Optional, SupportsFloat, SupportsInt, Union, Type
12
+ from typing import Any, Optional, SupportsFloat, SupportsInt, Union
13
13
 
14
14
  from elementpath.helpers import NUMERIC_INF_OR_NAN, INVALID_NUMERIC, collapse_white_spaces
15
15
  from .atomic_types import AnyAtomicType
@@ -166,7 +166,7 @@ class Integer(int, AnyAtomicType):
166
166
  int.__init__(self)
167
167
 
168
168
  @classmethod
169
- def __subclasshook__(cls, subclass: Type[Any]) -> bool:
169
+ def __subclasshook__(cls, subclass: type[Any]) -> bool:
170
170
  if cls is Integer:
171
171
  return issubclass(subclass, int) and not issubclass(subclass, bool)
172
172
  return NotImplemented # type: ignore[no-any-return,unused-ignore]
@@ -21,7 +21,7 @@ from .datetime import AbstractDateTime, Duration
21
21
  FloatArgType = Union[SupportsFloat, str, bytes]
22
22
 
23
23
  ####
24
- # Type proxies for basic Python datatypes: a proxy class creates
24
+ # type proxies for basic Python datatypes: a proxy class creates
25
25
  # and validates its Python datatype and virtual registered types.
26
26
 
27
27
 
@@ -155,7 +155,7 @@ class StringProxy(AnyAtomicType):
155
155
 
156
156
 
157
157
  ####
158
- # Type proxies for multiple type-checking in XPath expressions
158
+ # type proxies for multiple type-checking in XPath expressions
159
159
  class NumericTypeMeta(type):
160
160
  """Metaclass for checking numeric classes and instances."""
161
161
 
@@ -9,7 +9,7 @@
9
9
  #
10
10
  import operator
11
11
  from decimal import Decimal
12
- from typing import Any, Optional, Tuple, Union
12
+ from typing import Any, Optional, Union
13
13
 
14
14
  from elementpath.helpers import BOOLEAN_VALUES, get_double
15
15
  from .atomic_types import AnyAtomicType
@@ -52,7 +52,7 @@ class UntypedAtomic(AnyAtomicType):
52
52
  def __repr__(self) -> str:
53
53
  return '%s(%r)' % (self.__class__.__name__, self.value)
54
54
 
55
- def _get_operands(self, other: Any, force_float: bool = True) -> Tuple[Any, Any]:
55
+ def _get_operands(self, other: Any, force_float: bool = True) -> tuple[Any, Any]:
56
56
  """
57
57
  Returns a couple of operands, applying a cast to the instance value based on
58
58
  the type of the *other* argument.