elementpath 4.3.0__tar.gz → 4.5.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.
- {elementpath-4.3.0 → elementpath-4.5.0}/CHANGELOG.rst +14 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/PKG-INFO +44 -32
- {elementpath-4.3.0 → elementpath-4.5.0}/README.rst +42 -30
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/advanced.rst +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/conf.py +2 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/__init__.py +2 -4
- elementpath-4.5.0/elementpath/_typing.py +27 -0
- elementpath-4.5.0/elementpath/aliases.py +43 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/collations.py +3 -3
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/compare.py +18 -11
- elementpath-4.5.0/elementpath/datatypes/__init__.py +61 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/atomic_types.py +8 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/binary.py +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/datetime.py +16 -9
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/numeric.py +5 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/proxies.py +13 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/qname.py +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/string.py +4 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/untyped.py +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/datatypes/uri.py +1 -1
- elementpath-4.5.0/elementpath/decoder.py +176 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/etree.py +16 -7
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/exceptions.py +9 -7
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/helpers.py +4 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/namespaces.py +34 -29
- elementpath-4.5.0/elementpath/protocols.py +360 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/character_classes.py +2 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/codepoints.py +3 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/patterns.py +2 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/unicode_subsets.py +2 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/schema_proxy.py +30 -24
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/sequence_types.py +10 -10
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/serialization.py +21 -11
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/tdop.py +21 -17
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/tree_builders.py +18 -15
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/validators/__init__.py +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath1/_xpath1_axes.py +39 -24
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath1/_xpath1_functions.py +90 -63
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath1/_xpath1_operators.py +173 -174
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath1/xpath1_parser.py +53 -24
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath2/_xpath2_constructors.py +147 -89
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath2/_xpath2_functions.py +316 -225
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath2/_xpath2_operators.py +139 -101
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath2/xpath2_parser.py +25 -30
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/_xpath30_functions.py +219 -146
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/_xpath30_operators.py +45 -23
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/xpath30_helpers.py +4 -3
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/xpath30_parser.py +9 -9
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath31/_xpath31_functions.py +193 -142
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath31/_xpath31_operators.py +41 -27
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath31/xpath31_parser.py +7 -4
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath_context.py +96 -59
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath_nodes.py +79 -52
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath_selectors.py +10 -14
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath_tokens.py +291 -248
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath.egg-info/PKG-INFO +44 -32
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath.egg-info/SOURCES.txt +4 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath.egg-info/requires.txt +1 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/setup.py +2 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/execute_w3c_tests.py +4 -1
- elementpath-4.5.0/tests/mypy_tests/protocols.py +120 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_datatypes.py +5 -4
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_exceptions.py +4 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_regex.py +3 -3
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_selectors.py +22 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_tdop_parser.py +3 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_typing.py +8 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath1_parser.py +47 -50
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath2_constructors.py +4 -2
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath2_functions.py +10 -5
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath2_parser.py +70 -1
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath30.py +105 -37
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath31.py +42 -12
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath_context.py +1 -4
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath_nodes.py +23 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_xpath_tokens.py +9 -75
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/xpath_test_class.py +2 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tox.ini +20 -13
- elementpath-4.3.0/elementpath/datatypes/__init__.py +0 -124
- elementpath-4.3.0/elementpath/protocols.py +0 -187
- {elementpath-4.3.0 → elementpath-4.5.0}/.coveragerc +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/LICENSE +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/MANIFEST.in +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/Makefile +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/index.rst +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/introduction.rst +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/make.bat +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/pratt_api.rst +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/requirements.txt +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/doc/xpath_api.rst +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/py.typed +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/generate_categories.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/regex/unicode_categories.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/validators/analyze-string.xsd +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/validators/schema-for-json.xsd +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath1/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath2/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath3.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath30/_translation_maps.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath/xpath31/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath.egg-info/dependency_links.txt +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/elementpath.egg-info/top_level.txt +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/mypy.ini +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/requirements-dev.txt +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/setup.cfg +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/__init__.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/memory_profiling.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/mypy_tests/selectors.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/analyze-string.xsd +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/external_entity.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/sample.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/schema-for-json.xsd +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/unparsed_entity.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/unused_external_entity.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/unused_unparsed_entity.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/resources/with_entity.xml +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_collations.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_compare.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_elementpath.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_etree.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_helpers.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_namespaces.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_package.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_schema_context.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_schema_proxy.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_sequence_types.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_serialization.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_tree_builders.py +0 -0
- {elementpath-4.3.0 → elementpath-4.5.0}/tests/test_validators.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
CHANGELOG
|
|
3
3
|
*********
|
|
4
4
|
|
|
5
|
+
`v4.5.0`_ (2024-09-09)
|
|
6
|
+
======================
|
|
7
|
+
* Fix and clean node trees iteration methods (issue #72)
|
|
8
|
+
* Fix missing raw string for '[^\r\n]' (pull request #76)
|
|
9
|
+
* Full and more specific type annotations
|
|
10
|
+
|
|
11
|
+
`v4.4.0`_ (2024-03-11)
|
|
12
|
+
======================
|
|
13
|
+
* Improve stand-alone XPath functions builder (issue #70)
|
|
14
|
+
* Update tokens and parsers __repr__
|
|
15
|
+
* Fix static typing protocols to work with etree and XSD elements
|
|
16
|
+
|
|
5
17
|
`v4.3.0`_ (2024-02-17)
|
|
6
18
|
======================
|
|
7
19
|
* Change the purpose of the evaluation with a dynamic schema context
|
|
@@ -456,3 +468,5 @@ CHANGELOG
|
|
|
456
468
|
.. _v4.2.0: https://github.com/sissaschool/elementpath/compare/v4.1.5...v4.2.0
|
|
457
469
|
.. _v4.2.1: https://github.com/sissaschool/elementpath/compare/v4.2.0...v4.2.1
|
|
458
470
|
.. _v4.3.0: https://github.com/sissaschool/elementpath/compare/v4.2.1...v4.3.0
|
|
471
|
+
.. _v4.4.0: https://github.com/sissaschool/elementpath/compare/v4.3.0...v4.4.0
|
|
472
|
+
.. _v4.4.1: https://github.com/sissaschool/elementpath/compare/v4.4.0...v4.5.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: elementpath
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.5.0
|
|
4
4
|
Summary: XPath 1.0/2.0/3.0/3.1 parsers and selectors for ElementTree and lxml
|
|
5
5
|
Home-page: https://github.com/sissaschool/elementpath
|
|
6
6
|
Author: Davide Brunato
|
|
@@ -32,7 +32,7 @@ Provides-Extra: dev
|
|
|
32
32
|
Requires-Dist: tox; extra == "dev"
|
|
33
33
|
Requires-Dist: coverage; extra == "dev"
|
|
34
34
|
Requires-Dist: lxml; extra == "dev"
|
|
35
|
-
Requires-Dist: xmlschema>=
|
|
35
|
+
Requires-Dist: xmlschema>=3.3.2; extra == "dev"
|
|
36
36
|
Requires-Dist: Sphinx; extra == "dev"
|
|
37
37
|
Requires-Dist: memory-profiler; extra == "dev"
|
|
38
38
|
Requires-Dist: memray; extra == "dev"
|
|
@@ -76,11 +76,13 @@ You can install the package with *pip* in a Python 3.8+ environment::
|
|
|
76
76
|
|
|
77
77
|
For using it import the package and apply the selectors on ElementTree nodes:
|
|
78
78
|
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
>>>
|
|
82
|
-
>>>
|
|
83
|
-
|
|
79
|
+
.. code-block:: pycon
|
|
80
|
+
|
|
81
|
+
>>> import elementpath
|
|
82
|
+
>>> from xml.etree import ElementTree
|
|
83
|
+
>>> root = ElementTree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
84
|
+
>>> elementpath.select(root, '/A/B2/*')
|
|
85
|
+
[<Element 'C1' at ...>, <Element 'C2' at ...>, <Element 'C3' at ...>]
|
|
84
86
|
|
|
85
87
|
The *select* API provides the standard XPath result format that is a list or an elementary
|
|
86
88
|
datatype's value. If you want only to iterate over results you can use the generator function
|
|
@@ -89,52 +91,62 @@ datatype's value. If you want only to iterate over results you can use the gener
|
|
|
89
91
|
The selectors API works also using XML data trees based on the `lxml.etree <http://lxml.de>`_
|
|
90
92
|
library:
|
|
91
93
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
>>>
|
|
95
|
-
>>>
|
|
96
|
-
|
|
94
|
+
.. code-block:: pycon
|
|
95
|
+
|
|
96
|
+
>>> import elementpath
|
|
97
|
+
>>> import lxml.etree as etree
|
|
98
|
+
>>> root = etree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
99
|
+
>>> elementpath.select(root, '/A/B2/*')
|
|
100
|
+
[<Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
97
101
|
|
|
98
102
|
When you need to apply the same XPath expression to several XML data you can also use the
|
|
99
103
|
*Selector* class, creating an instance and then using it to apply the path on distinct XML
|
|
100
104
|
data:
|
|
101
105
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
>>>
|
|
105
|
-
>>>
|
|
106
|
-
>>> selector.
|
|
107
|
-
|
|
108
|
-
>>>
|
|
109
|
-
|
|
110
|
-
|
|
106
|
+
.. code-block:: pycon
|
|
107
|
+
|
|
108
|
+
>>> import elementpath
|
|
109
|
+
>>> import lxml.etree as etree
|
|
110
|
+
>>> selector = elementpath.Selector('/A/*/*')
|
|
111
|
+
>>> root = etree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
112
|
+
>>> selector.select(root)
|
|
113
|
+
[<Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
114
|
+
>>> root = etree.XML('<A><B1><C0/></B1><B2><C1/><C2/><C3/></B2></A>')
|
|
115
|
+
>>> selector.select(root)
|
|
116
|
+
[<Element C0 at ...>, <Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
111
117
|
|
|
112
118
|
Public API classes and functions are described into the
|
|
113
119
|
`elementpath manual on the "Read the Docs" site <http://elementpath.readthedocs.io/en/latest/>`_.
|
|
114
120
|
|
|
115
121
|
For default the XPath 2.0 is used. If you need XPath 1.0 parser provide the *parser* argument:
|
|
116
122
|
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
>>>
|
|
120
|
-
>>>
|
|
121
|
-
|
|
123
|
+
.. code-block:: pycon
|
|
124
|
+
|
|
125
|
+
>>> from elementpath import select, XPath1Parser
|
|
126
|
+
>>> from xml.etree import ElementTree
|
|
127
|
+
>>> root = ElementTree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
128
|
+
>>> select(root, '/A/B2/*', parser=XPath1Parser)
|
|
129
|
+
[<Element 'C1' at ...>, <Element 'C2' at ...>, <Element 'C3' at ...>]
|
|
122
130
|
|
|
123
131
|
For XPath 3.0/3.1 import the parser from *elementpath.xpath3* subpackage, that is not loaded
|
|
124
132
|
for default:
|
|
125
133
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
134
|
+
.. code-block:: pycon
|
|
135
|
+
|
|
136
|
+
>>> from elementpath.xpath3 import XPath3Parser
|
|
137
|
+
>>> select(root, 'math:atan(1.0e0)', parser=XPath3Parser)
|
|
138
|
+
0.7853981633974483
|
|
129
139
|
|
|
130
140
|
Note: *XPath3Parser* is an alias of *XPath31Parser*.
|
|
131
141
|
|
|
132
142
|
If you need only XPath 3.0 you can also use a more specific subpackage,
|
|
133
143
|
avoiding the loading of XPath 3.1 implementation:
|
|
134
144
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
145
|
+
.. code-block:: pycon
|
|
146
|
+
|
|
147
|
+
>>> from elementpath.xpath30 import XPath30Parser
|
|
148
|
+
>>> select(root, 'math:atan(1.0e0)', parser=XPath30Parser)
|
|
149
|
+
0.7853981633974483
|
|
138
150
|
|
|
139
151
|
|
|
140
152
|
Contributing
|
|
@@ -34,11 +34,13 @@ You can install the package with *pip* in a Python 3.8+ environment::
|
|
|
34
34
|
|
|
35
35
|
For using it import the package and apply the selectors on ElementTree nodes:
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
>>>
|
|
40
|
-
>>>
|
|
41
|
-
|
|
37
|
+
.. code-block:: pycon
|
|
38
|
+
|
|
39
|
+
>>> import elementpath
|
|
40
|
+
>>> from xml.etree import ElementTree
|
|
41
|
+
>>> root = ElementTree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
42
|
+
>>> elementpath.select(root, '/A/B2/*')
|
|
43
|
+
[<Element 'C1' at ...>, <Element 'C2' at ...>, <Element 'C3' at ...>]
|
|
42
44
|
|
|
43
45
|
The *select* API provides the standard XPath result format that is a list or an elementary
|
|
44
46
|
datatype's value. If you want only to iterate over results you can use the generator function
|
|
@@ -47,52 +49,62 @@ datatype's value. If you want only to iterate over results you can use the gener
|
|
|
47
49
|
The selectors API works also using XML data trees based on the `lxml.etree <http://lxml.de>`_
|
|
48
50
|
library:
|
|
49
51
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
>>>
|
|
53
|
-
>>>
|
|
54
|
-
|
|
52
|
+
.. code-block:: pycon
|
|
53
|
+
|
|
54
|
+
>>> import elementpath
|
|
55
|
+
>>> import lxml.etree as etree
|
|
56
|
+
>>> root = etree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
57
|
+
>>> elementpath.select(root, '/A/B2/*')
|
|
58
|
+
[<Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
55
59
|
|
|
56
60
|
When you need to apply the same XPath expression to several XML data you can also use the
|
|
57
61
|
*Selector* class, creating an instance and then using it to apply the path on distinct XML
|
|
58
62
|
data:
|
|
59
63
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
>>>
|
|
63
|
-
>>>
|
|
64
|
-
>>> selector.
|
|
65
|
-
|
|
66
|
-
>>>
|
|
67
|
-
|
|
68
|
-
|
|
64
|
+
.. code-block:: pycon
|
|
65
|
+
|
|
66
|
+
>>> import elementpath
|
|
67
|
+
>>> import lxml.etree as etree
|
|
68
|
+
>>> selector = elementpath.Selector('/A/*/*')
|
|
69
|
+
>>> root = etree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
70
|
+
>>> selector.select(root)
|
|
71
|
+
[<Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
72
|
+
>>> root = etree.XML('<A><B1><C0/></B1><B2><C1/><C2/><C3/></B2></A>')
|
|
73
|
+
>>> selector.select(root)
|
|
74
|
+
[<Element C0 at ...>, <Element C1 at ...>, <Element C2 at ...>, <Element C3 at ...>]
|
|
69
75
|
|
|
70
76
|
Public API classes and functions are described into the
|
|
71
77
|
`elementpath manual on the "Read the Docs" site <http://elementpath.readthedocs.io/en/latest/>`_.
|
|
72
78
|
|
|
73
79
|
For default the XPath 2.0 is used. If you need XPath 1.0 parser provide the *parser* argument:
|
|
74
80
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
>>>
|
|
78
|
-
>>>
|
|
79
|
-
|
|
81
|
+
.. code-block:: pycon
|
|
82
|
+
|
|
83
|
+
>>> from elementpath import select, XPath1Parser
|
|
84
|
+
>>> from xml.etree import ElementTree
|
|
85
|
+
>>> root = ElementTree.XML('<A><B1/><B2><C1/><C2/><C3/></B2></A>')
|
|
86
|
+
>>> select(root, '/A/B2/*', parser=XPath1Parser)
|
|
87
|
+
[<Element 'C1' at ...>, <Element 'C2' at ...>, <Element 'C3' at ...>]
|
|
80
88
|
|
|
81
89
|
For XPath 3.0/3.1 import the parser from *elementpath.xpath3* subpackage, that is not loaded
|
|
82
90
|
for default:
|
|
83
91
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
92
|
+
.. code-block:: pycon
|
|
93
|
+
|
|
94
|
+
>>> from elementpath.xpath3 import XPath3Parser
|
|
95
|
+
>>> select(root, 'math:atan(1.0e0)', parser=XPath3Parser)
|
|
96
|
+
0.7853981633974483
|
|
87
97
|
|
|
88
98
|
Note: *XPath3Parser* is an alias of *XPath31Parser*.
|
|
89
99
|
|
|
90
100
|
If you need only XPath 3.0 you can also use a more specific subpackage,
|
|
91
101
|
avoiding the loading of XPath 3.1 implementation:
|
|
92
102
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
103
|
+
.. code-block:: pycon
|
|
104
|
+
|
|
105
|
+
>>> from elementpath.xpath30 import XPath30Parser
|
|
106
|
+
>>> select(root, 'math:atan(1.0e0)', parser=XPath30Parser)
|
|
107
|
+
0.7853981633974483
|
|
96
108
|
|
|
97
109
|
|
|
98
110
|
Contributing
|
|
@@ -29,9 +29,9 @@ copyright = '2018-2024, SISSA (International School for Advanced Studies)'
|
|
|
29
29
|
author = 'Davide Brunato'
|
|
30
30
|
|
|
31
31
|
# The short X.Y version
|
|
32
|
-
version = '4.
|
|
32
|
+
version = '4.5'
|
|
33
33
|
# The full version, including alpha/beta/rc tags
|
|
34
|
-
release = '4.
|
|
34
|
+
release = '4.5.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.
|
|
10
|
+
__version__ = '4.5.0'
|
|
11
11
|
__author__ = "Davide Brunato"
|
|
12
12
|
__contact__ = "brunato@sissa.it"
|
|
13
13
|
__copyright__ = "Copyright 2018-2024, SISSA"
|
|
@@ -38,8 +38,6 @@ from .xpath_selectors import select, iter_select, Selector
|
|
|
38
38
|
from .schema_proxy import AbstractSchemaProxy
|
|
39
39
|
from .regex import RegexError, translate_pattern
|
|
40
40
|
|
|
41
|
-
TypedElement = ElementNode # for backward compatibility with xmlschema<=1.10.0
|
|
42
|
-
|
|
43
41
|
__all__ = ['datatypes', 'protocols', 'etree', 'ElementPathError', 'MissingContextError',
|
|
44
42
|
'ElementPathKeyError', 'ElementPathZeroDivisionError', 'ElementPathNameError',
|
|
45
43
|
'ElementPathOverflowError', 'ElementPathRuntimeError', 'ElementPathSyntaxError',
|
|
@@ -47,7 +45,7 @@ __all__ = ['datatypes', 'protocols', 'etree', 'ElementPathError', 'MissingContex
|
|
|
47
45
|
'XPathContext', 'XPathSchemaContext', 'XPathNode', 'DocumentNode',
|
|
48
46
|
'ElementNode', 'AttributeNode', 'NamespaceNode', 'CommentNode',
|
|
49
47
|
'ProcessingInstructionNode', 'TextNode', 'LazyElementNode',
|
|
50
|
-
'SchemaElementNode', '
|
|
48
|
+
'SchemaElementNode', 'get_node_tree', 'build_node_tree',
|
|
51
49
|
'build_lxml_node_tree', 'build_schema_node_tree', 'XPathToken',
|
|
52
50
|
'XPathFunction', 'XPath1Parser', 'XPath2Parser', 'select', 'iter_select',
|
|
53
51
|
'Selector', 'AbstractSchemaProxy', 'RegexError', 'translate_pattern']
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c), 2024, SISSA (International School for Advanced Studies).
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# This file is distributed under the terms of the MIT License.
|
|
5
|
+
# See the file 'LICENSE' in the root directory of the present
|
|
6
|
+
# distribution, or http://opensource.org/licenses/MIT.
|
|
7
|
+
#
|
|
8
|
+
# @author Davide Brunato <brunato@sissa.it>
|
|
9
|
+
#
|
|
10
|
+
"""
|
|
11
|
+
Version related imports for subscriptable types for type annotations (no builtins).
|
|
12
|
+
"""
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
if sys.version_info < (3, 9):
|
|
16
|
+
from typing import Callable, Counter, Deque, Iterable, Iterator, \
|
|
17
|
+
Mapping, Match, MutableMapping, MutableSequence, MutableSet, Pattern, Sequence
|
|
18
|
+
else:
|
|
19
|
+
from collections import deque as Deque, Counter # noqa
|
|
20
|
+
from collections.abc import Callable, Iterable, Iterator, Mapping, MutableMapping, \
|
|
21
|
+
MutableSequence, MutableSet, Sequence
|
|
22
|
+
from re import Match, Pattern
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ['Callable', 'Counter', 'Deque', 'Iterable', 'Iterator', 'Match',
|
|
26
|
+
'Mapping', 'MutableMapping', 'MutableSequence', 'MutableSet',
|
|
27
|
+
'Pattern', 'Sequence']
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c), 2021, SISSA (International School for Advanced Studies).
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# This file is distributed under the terms of the MIT License.
|
|
5
|
+
# See the file 'LICENSE' in the root directory of the present
|
|
6
|
+
# distribution, or http://opensource.org/licenses/MIT.
|
|
7
|
+
#
|
|
8
|
+
# @author Davide Brunato <brunato@sissa.it>
|
|
9
|
+
#
|
|
10
|
+
"""
|
|
11
|
+
Common type hints aliases for elementpath.
|
|
12
|
+
"""
|
|
13
|
+
from typing import Any, List, Optional, NoReturn, Tuple, Type, TYPE_CHECKING, TypeVar, Union
|
|
14
|
+
|
|
15
|
+
from elementpath._typing import MutableMapping
|
|
16
|
+
|
|
17
|
+
##
|
|
18
|
+
# Type aliases
|
|
19
|
+
NamespacesType = MutableMapping[str, str]
|
|
20
|
+
NsmapType = MutableMapping[Optional[str], str] # compatible with the nsmap of lxml Element
|
|
21
|
+
AnyNsmapType = Union[NamespacesType, NsmapType, None] # for composition and function arguments
|
|
22
|
+
|
|
23
|
+
NargsType = Optional[Union[int, Tuple[int, Optional[int]]]]
|
|
24
|
+
ClassCheckType = Union[Type[Any], Tuple[Type[Any], ...]]
|
|
25
|
+
|
|
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, ...]]
|
|
30
|
+
|
|
31
|
+
if TYPE_CHECKING:
|
|
32
|
+
from elementpath.datatypes import AtomicType, ArithmeticType, NumericType
|
|
33
|
+
from elementpath.xpath_nodes import ChildNodeType, ParentNodeType
|
|
34
|
+
from elementpath.tree_builders import RootArgType
|
|
35
|
+
from elementpath.xpath_context import ContextType, FunctionArgType, ItemType, \
|
|
36
|
+
ItemArgType, ValueType
|
|
37
|
+
from elementpath.xpath_tokens import XPathParserType, XPathTokenType
|
|
38
|
+
|
|
39
|
+
__all__ = ['NamespacesType', 'NsmapType', 'AnyNsmapType', 'NargsType',
|
|
40
|
+
'ClassCheckType', 'Emptiable', 'SequenceType', 'InputType',
|
|
41
|
+
'AtomicType', 'ArithmeticType', 'NumericType', 'ChildNodeType',
|
|
42
|
+
'ParentNodeType', 'RootArgType', 'ContextType', 'FunctionArgType',
|
|
43
|
+
'ItemType', 'ItemArgType', 'ValueType', 'XPathParserType', 'XPathTokenType']
|
|
@@ -14,7 +14,7 @@ from types import TracebackType
|
|
|
14
14
|
from typing import TYPE_CHECKING, Any, Optional, Tuple, Type, Union
|
|
15
15
|
from urllib.parse import urljoin, urlsplit
|
|
16
16
|
|
|
17
|
-
from .exceptions import xpath_error
|
|
17
|
+
from elementpath.exceptions import xpath_error
|
|
18
18
|
|
|
19
19
|
if TYPE_CHECKING:
|
|
20
20
|
from .xpath_tokens import XPathToken
|
|
@@ -173,8 +173,8 @@ class CollationManager(context_class_base):
|
|
|
173
173
|
def find(self, a: str, b: str) -> int:
|
|
174
174
|
return self.strxfrm(a).find(self.strxfrm(b))
|
|
175
175
|
|
|
176
|
-
def startswith(self, a: str, b: str) ->
|
|
176
|
+
def startswith(self, a: str, b: str) -> bool:
|
|
177
177
|
return self.strxfrm(a).startswith(self.strxfrm(b))
|
|
178
178
|
|
|
179
|
-
def endswith(self, a: str, b: str) ->
|
|
179
|
+
def endswith(self, a: str, b: str) -> bool:
|
|
180
180
|
return self.strxfrm(a).endswith(self.strxfrm(b))
|
|
@@ -11,15 +11,16 @@ import math
|
|
|
11
11
|
from decimal import Decimal
|
|
12
12
|
from functools import cmp_to_key
|
|
13
13
|
from itertools import zip_longest
|
|
14
|
-
from typing import Any,
|
|
14
|
+
from typing import Any, Optional
|
|
15
15
|
|
|
16
|
-
from .
|
|
17
|
-
from .
|
|
18
|
-
from .
|
|
19
|
-
from .
|
|
20
|
-
from .
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
from elementpath._typing import Callable, Iterable, Iterator
|
|
17
|
+
from elementpath.protocols import ElementProtocol
|
|
18
|
+
from elementpath.exceptions import xpath_error
|
|
19
|
+
from elementpath.datatypes import UntypedAtomic, AnyURI, AbstractQName
|
|
20
|
+
from elementpath.collations import UNICODE_CODEPOINT_COLLATION, CollationManager
|
|
21
|
+
from elementpath.xpath_nodes import XPathNode, ElementNode, AttributeNode, \
|
|
22
|
+
NamespaceNode, TextNode, CommentNode, ProcessingInstructionNode, DocumentNode
|
|
23
|
+
from elementpath.xpath_tokens import XPathToken, XPathFunction, XPathMap, XPathArray
|
|
23
24
|
|
|
24
25
|
|
|
25
26
|
def deep_equal(seq1: Iterable[Any],
|
|
@@ -39,8 +40,14 @@ def deep_equal(seq1: Iterable[Any],
|
|
|
39
40
|
elif len(e1) != len(e2) or len(e1.attrib) != len(e2.attrib):
|
|
40
41
|
return False
|
|
41
42
|
|
|
42
|
-
|
|
43
|
-
|
|
43
|
+
try:
|
|
44
|
+
items1 = {(cm.strxfrm(k or ''), cm.strxfrm(v)) # type: ignore[arg-type]
|
|
45
|
+
for k, v in e1.attrib.items()}
|
|
46
|
+
items2 = {(cm.strxfrm(k or ''), cm.strxfrm(v)) # type: ignore[arg-type]
|
|
47
|
+
for k, v in e2.attrib.items()}
|
|
48
|
+
except TypeError:
|
|
49
|
+
return False
|
|
50
|
+
|
|
44
51
|
if items1 != items2:
|
|
45
52
|
return False
|
|
46
53
|
return all(etree_deep_equal(c1, c2) for c1, c2 in zip(e1, e2))
|
|
@@ -274,7 +281,7 @@ def deep_compare(obj1: Any,
|
|
|
274
281
|
|
|
275
282
|
if isinstance(value1, AttributeNode):
|
|
276
283
|
assert isinstance(value2, AttributeNode)
|
|
277
|
-
result = cm.strcoll(value1.name, value2.name)
|
|
284
|
+
result = cm.strcoll(value1.name or '', value2.name or '')
|
|
278
285
|
if result:
|
|
279
286
|
return result
|
|
280
287
|
elif isinstance(value1, NamespaceNode):
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (c), 2018-2020, SISSA (International School for Advanced Studies).
|
|
3
|
+
# All rights reserved.
|
|
4
|
+
# This file is distributed under the terms of the MIT License.
|
|
5
|
+
# See the file 'LICENSE' in the root directory of the present
|
|
6
|
+
# distribution, or http://opensource.org/licenses/MIT.
|
|
7
|
+
#
|
|
8
|
+
# @author Davide Brunato <brunato@sissa.it>
|
|
9
|
+
#
|
|
10
|
+
"""
|
|
11
|
+
XSD atomic datatypes subpackage. Includes a class for UntypedAtomic data and
|
|
12
|
+
classes for other XSD built-in types. This subpackage raises only built-in
|
|
13
|
+
exceptions in order to be reusable in other packages.
|
|
14
|
+
"""
|
|
15
|
+
from decimal import Decimal
|
|
16
|
+
from typing import Union
|
|
17
|
+
|
|
18
|
+
from .atomic_types import xsd10_atomic_types, xsd11_atomic_types, \
|
|
19
|
+
AtomicTypeMeta, AnyAtomicType
|
|
20
|
+
from .untyped import UntypedAtomic
|
|
21
|
+
from .qname import AbstractQName, QName, Notation
|
|
22
|
+
from .numeric import Float10, Float, Integer, Int, NegativeInteger, \
|
|
23
|
+
PositiveInteger, NonNegativeInteger, NonPositiveInteger, Long, \
|
|
24
|
+
Short, Byte, UnsignedByte, UnsignedInt, UnsignedLong, UnsignedShort
|
|
25
|
+
from .string import NormalizedString, XsdToken, Name, NCName, NMToken, Id, \
|
|
26
|
+
Idref, Language, Entity
|
|
27
|
+
from .uri import AnyURI
|
|
28
|
+
from .binary import AbstractBinary, Base64Binary, HexBinary
|
|
29
|
+
from .datetime import AbstractDateTime, DateTime10, DateTime, DateTimeStamp, \
|
|
30
|
+
Date10, Date, GregorianDay, GregorianMonth, GregorianYear, GregorianYear10, \
|
|
31
|
+
GregorianMonthDay, GregorianYearMonth, GregorianYearMonth10, Time, Timezone, \
|
|
32
|
+
Duration, DayTimeDuration, YearMonthDuration, OrderedDateTime
|
|
33
|
+
from .proxies import BooleanProxy, DecimalProxy, DoubleProxy10, DoubleProxy, \
|
|
34
|
+
StringProxy, NumericProxy, ArithmeticProxy
|
|
35
|
+
|
|
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
|
+
###
|
|
42
|
+
# Aliases for type annotations
|
|
43
|
+
AtomicType = Union[str, int, float, Decimal, bool, AnyAtomicType]
|
|
44
|
+
NumericType = Union[int, float, Decimal]
|
|
45
|
+
ArithmeticType = Union[NumericType, AbstractDateTime, Duration, UntypedAtomic]
|
|
46
|
+
DatetimeValueType = AbstractDateTime # keep until v5.0 for backward compatibility
|
|
47
|
+
|
|
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',
|
|
52
|
+
'GregorianYear10', 'GregorianYear', 'GregorianYearMonth10', 'GregorianYearMonth',
|
|
53
|
+
'Timezone', 'Duration', 'YearMonthDuration', 'DayTimeDuration', 'StringProxy',
|
|
54
|
+
'NormalizedString', 'XsdToken', 'Language', 'Name', 'NCName', 'Id', 'Idref',
|
|
55
|
+
'Entity', 'NMToken', 'Base64Binary', 'HexBinary', 'Float10', 'Float',
|
|
56
|
+
'Integer', 'NonPositiveInteger', 'NegativeInteger', 'Long', 'Int', 'Short',
|
|
57
|
+
'Byte', 'NonNegativeInteger', 'PositiveInteger', 'UnsignedLong', 'UnsignedInt',
|
|
58
|
+
'UnsignedShort', 'UnsignedByte', 'AnyURI', 'Notation', 'QName', 'BooleanProxy',
|
|
59
|
+
'DecimalProxy', 'DoubleProxy10', 'DoubleProxy', 'UntypedAtomic', 'AbstractBinary',
|
|
60
|
+
'AtomicType', 'DatetimeValueType', 'OrderedDateTime', 'AbstractQName',
|
|
61
|
+
'NumericType', 'ArithmeticType']
|
|
@@ -7,10 +7,12 @@
|
|
|
7
7
|
#
|
|
8
8
|
# @author Davide Brunato <brunato@sissa.it>
|
|
9
9
|
#
|
|
10
|
-
from abc import ABCMeta
|
|
11
|
-
from typing import Any, Dict, Optional,
|
|
10
|
+
from abc import ABCMeta, abstractmethod
|
|
11
|
+
from typing import Any, Dict, Optional, Tuple, Type
|
|
12
12
|
import re
|
|
13
13
|
|
|
14
|
+
from elementpath._typing import Pattern
|
|
15
|
+
|
|
14
16
|
XSD_NAMESPACE = "http://www.w3.org/2001/XMLSchema"
|
|
15
17
|
|
|
16
18
|
###
|
|
@@ -98,3 +100,7 @@ class AtomicTypeMeta(ABCMeta):
|
|
|
98
100
|
|
|
99
101
|
class AnyAtomicType(metaclass=AtomicTypeMeta):
|
|
100
102
|
name = 'anyAtomicType'
|
|
103
|
+
|
|
104
|
+
@abstractmethod
|
|
105
|
+
def __init__(self, value: Any) -> None:
|
|
106
|
+
raise NotImplementedError()
|
|
@@ -12,7 +12,7 @@ from typing import Any, Callable, Union
|
|
|
12
12
|
import re
|
|
13
13
|
import codecs
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from elementpath.helpers import collapse_white_spaces
|
|
16
16
|
from .atomic_types import AnyAtomicType
|
|
17
17
|
from .untyped import UntypedAtomic
|
|
18
18
|
|
|
@@ -14,9 +14,10 @@ import re
|
|
|
14
14
|
import datetime
|
|
15
15
|
from calendar import isleap
|
|
16
16
|
from decimal import Decimal, Context
|
|
17
|
-
from typing import cast, Any,
|
|
17
|
+
from typing import cast, Any, Dict, Optional, Tuple, Type, TypeVar, Union
|
|
18
18
|
|
|
19
|
-
from
|
|
19
|
+
from elementpath._typing import Callable
|
|
20
|
+
from elementpath.helpers import MONTH_DAYS_LEAP, MONTH_DAYS, DAYS_IN_4Y, \
|
|
20
21
|
DAYS_IN_100Y, DAYS_IN_400Y, days_from_common_era, adjust_day, \
|
|
21
22
|
normalized_seconds, months2days, round_number
|
|
22
23
|
from .atomic_types import AnyAtomicType
|
|
@@ -112,6 +113,9 @@ class Timezone(datetime.tzinfo):
|
|
|
112
113
|
raise TypeError("fromutc() argument must be a datetime.datetime instance")
|
|
113
114
|
|
|
114
115
|
|
|
116
|
+
_DT = TypeVar('_DT', bound='AbstractDateTime')
|
|
117
|
+
|
|
118
|
+
|
|
115
119
|
class AbstractDateTime(AnyAtomicType):
|
|
116
120
|
"""
|
|
117
121
|
A class for representing XSD date/time objects. It uses and internal datetime.datetime
|
|
@@ -260,8 +264,8 @@ class AbstractDateTime(AnyAtomicType):
|
|
|
260
264
|
return self._dt.isocalendar()
|
|
261
265
|
|
|
262
266
|
@classmethod
|
|
263
|
-
def fromstring(cls, datetime_string: str, tzinfo: Optional[Timezone] = None) \
|
|
264
|
-
->
|
|
267
|
+
def fromstring(cls: Type[_DT], datetime_string: str, tzinfo: Optional[Timezone] = None) \
|
|
268
|
+
-> _DT:
|
|
265
269
|
"""
|
|
266
270
|
Creates an XSD date/time instance from a string formatted value.
|
|
267
271
|
|
|
@@ -311,13 +315,13 @@ class AbstractDateTime(AnyAtomicType):
|
|
|
311
315
|
return cls(tzinfo=tzinfo, **kwargs)
|
|
312
316
|
|
|
313
317
|
@classmethod
|
|
314
|
-
def fromdatetime(cls, dt: Union[datetime.datetime, datetime.date, datetime.time],
|
|
315
|
-
year: Optional[int] = None) ->
|
|
318
|
+
def fromdatetime(cls: Type[_DT], dt: Union[datetime.datetime, datetime.date, datetime.time],
|
|
319
|
+
year: Optional[int] = None) -> _DT:
|
|
316
320
|
"""
|
|
317
321
|
Creates an XSD date/time instance from a datetime.datetime/date/time instance.
|
|
318
322
|
|
|
319
323
|
:param dt: the datetime, date or time instance that stores the XSD Date/Time value.
|
|
320
|
-
:param year: if
|
|
324
|
+
:param year: if a year is provided the created instance refers to it and the \
|
|
321
325
|
possibly present *dt.year* part is ignored.
|
|
322
326
|
:return: an AbstractDateTime concrete subclass instance.
|
|
323
327
|
"""
|
|
@@ -331,7 +335,7 @@ class AbstractDateTime(AnyAtomicType):
|
|
|
331
335
|
kwargs['year'] = year
|
|
332
336
|
return cls(**kwargs)
|
|
333
337
|
|
|
334
|
-
# Python can't
|
|
338
|
+
# Python can't compare offset-naive and offset-aware datetimes
|
|
335
339
|
def _get_operands(self, other: object) -> Tuple[datetime.datetime, datetime.datetime]:
|
|
336
340
|
if isinstance(other, (self.__class__, datetime.datetime)) or \
|
|
337
341
|
isinstance(self, other.__class__):
|
|
@@ -755,6 +759,9 @@ class Time(AbstractDateTime):
|
|
|
755
759
|
raise TypeError("wrong type %r for operand %r" % (type(other), other))
|
|
756
760
|
|
|
757
761
|
|
|
762
|
+
_D = TypeVar('_D', bound='Duration')
|
|
763
|
+
|
|
764
|
+
|
|
758
765
|
class Duration(AnyAtomicType):
|
|
759
766
|
"""
|
|
760
767
|
Base class for the XSD duration types.
|
|
@@ -817,7 +824,7 @@ class Duration(AnyAtomicType):
|
|
|
817
824
|
return value
|
|
818
825
|
|
|
819
826
|
@classmethod
|
|
820
|
-
def fromstring(cls, text: str) ->
|
|
827
|
+
def fromstring(cls: Type[_D], text: str) -> _D:
|
|
821
828
|
"""
|
|
822
829
|
Creates a Duration instance from a formatted XSD duration string.
|
|
823
830
|
|