elementpath 4.6.0__tar.gz → 4.8.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.6.0 → elementpath-4.8.0}/CHANGELOG.rst +14 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/PKG-INFO +12 -2
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/advanced.rst +13 -8
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/conf.py +3 -3
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/__init__.py +11 -12
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/aliases.py +1 -2
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/compare.py +33 -33
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/datetime.py +8 -1
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/numeric.py +1 -1
- elementpath-4.8.0/elementpath/decoder.py +170 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/etree.py +26 -6
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/protocols.py +41 -12
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/schema_proxy.py +63 -7
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/sequence_types.py +9 -8
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/serialization.py +6 -6
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/tree_builders.py +97 -68
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath1/_xpath1_axes.py +6 -4
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath1/_xpath1_functions.py +12 -10
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath1/_xpath1_operators.py +32 -120
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath1/xpath1_parser.py +21 -4
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath2/_xpath2_constructors.py +14 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath2/_xpath2_functions.py +45 -43
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath2/_xpath2_operators.py +22 -33
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath2/xpath2_parser.py +3 -21
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/_xpath30_functions.py +27 -67
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/_xpath30_operators.py +2 -6
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath31/_xpath31_functions.py +5 -5
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath31/_xpath31_operators.py +17 -8
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath_context.py +146 -50
- elementpath-4.8.0/elementpath/xpath_nodes.py +1752 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath_selectors.py +70 -33
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath_tokens.py +187 -264
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath.egg-info/PKG-INFO +12 -2
- {elementpath-4.6.0 → elementpath-4.8.0}/setup.py +1 -1
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/execute_w3c_tests.py +7 -3
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_compare.py +5 -5
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_datatypes.py +35 -9
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_schema_context.py +0 -79
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_schema_proxy.py +39 -57
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_selectors.py +44 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_sequence_types.py +1 -1
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_serialization.py +2 -2
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath1_parser.py +6 -6
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath2_constructors.py +9 -7
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath2_functions.py +7 -6
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath2_parser.py +48 -34
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath30.py +10 -5
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath31.py +33 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath_context.py +22 -18
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath_nodes.py +77 -62
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_xpath_tokens.py +38 -285
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/xpath_test_class.py +5 -4
- {elementpath-4.6.0 → elementpath-4.8.0}/tox.ini +20 -9
- elementpath-4.6.0/elementpath/decoder.py +0 -176
- elementpath-4.6.0/elementpath/xpath_nodes.py +0 -1048
- {elementpath-4.6.0 → elementpath-4.8.0}/.coveragerc +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/LICENSE +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/MANIFEST.in +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/README.rst +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/Makefile +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/index.rst +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/introduction.rst +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/make.bat +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/pratt_api.rst +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/requirements.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/doc/xpath_api.rst +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/_typing.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/collations.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/atomic_types.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/binary.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/proxies.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/qname.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/string.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/untyped.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/datatypes/uri.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/exceptions.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/helpers.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/namespaces.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/py.typed +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/character_classes.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/codepoints.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/patterns.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/unicode_blocks.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/unicode_categories.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/regex/unicode_subsets.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/tdop.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/validators/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/validators/analyze-string.xsd +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/validators/schema-for-json.xsd +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath1/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath2/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath3.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/_translation_maps.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/xpath30_helpers.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath30/xpath30_parser.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath31/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath/xpath31/xpath31_parser.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath.egg-info/SOURCES.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath.egg-info/dependency_links.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath.egg-info/requires.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/elementpath.egg-info/top_level.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/mypy.ini +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/requirements-dev.txt +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/scripts/generate_codepoints.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/setup.cfg +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/__init__.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/memory_profiling.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/mypy_tests/advanced.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/mypy_tests/protocols.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/mypy_tests/selectors.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/analyze-string.xsd +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/external_entity.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/sample.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/schema-for-json.xsd +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/unparsed_entity.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/unused_external_entity.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/unused_unparsed_entity.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/resources/with_entity.xml +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_collations.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_elementpath.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_etree.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_exceptions.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_helpers.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_namespaces.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_package.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_regex.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_tdop_parser.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_tree_builders.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_typing.py +0 -0
- {elementpath-4.6.0 → elementpath-4.8.0}/tests/test_validators.py +0 -0
|
@@ -2,6 +2,18 @@
|
|
|
2
2
|
CHANGELOG
|
|
3
3
|
*********
|
|
4
4
|
|
|
5
|
+
`v4.8.0`_ (2025-03-03)
|
|
6
|
+
======================
|
|
7
|
+
* Add full PSVI type labeling in XDM to solve type errors with XSD 1.1 assertions
|
|
8
|
+
* Add *schema* optional argument to dynamic context
|
|
9
|
+
* Add a RootToken as a proxy of the parsed token tree for compatibility with xmlschema<=3.4.3
|
|
10
|
+
* Extend XDM to split ElementTree/lxml processing from schema nodes and to allow future extensions
|
|
11
|
+
|
|
12
|
+
`v4.7.0`_ (2024-12-20)
|
|
13
|
+
======================
|
|
14
|
+
* Fix *fragment* argument usage (issue #81)
|
|
15
|
+
* Fix constructors nud() to skip argument check with XP31+ arrow operator (issue #83)
|
|
16
|
+
|
|
5
17
|
`v4.6.0`_ (2024-10-27)
|
|
6
18
|
======================
|
|
7
19
|
* Fix XsdAttributeGroupProtocol
|
|
@@ -478,3 +490,5 @@ CHANGELOG
|
|
|
478
490
|
.. _v4.4.0: https://github.com/sissaschool/elementpath/compare/v4.3.0...v4.4.0
|
|
479
491
|
.. _v4.5.0: https://github.com/sissaschool/elementpath/compare/v4.4.0...v4.5.0
|
|
480
492
|
.. _v4.6.0: https://github.com/sissaschool/elementpath/compare/v4.5.0...v4.6.0
|
|
493
|
+
.. _v4.7.0: https://github.com/sissaschool/elementpath/compare/v4.6.0...v4.7.0
|
|
494
|
+
.. _v4.8.0: https://github.com/sissaschool/elementpath/compare/v4.7.0...v4.8.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.2
|
|
2
2
|
Name: elementpath
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.8.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
|
|
@@ -40,6 +40,16 @@ Requires-Dist: memray; extra == "dev"
|
|
|
40
40
|
Requires-Dist: flake8; extra == "dev"
|
|
41
41
|
Requires-Dist: mypy; extra == "dev"
|
|
42
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
|
|
43
53
|
|
|
44
54
|
***********
|
|
45
55
|
elementpath
|
|
@@ -22,6 +22,11 @@ having as result a tree of tokens:
|
|
|
22
22
|
>>> token = parser.parse('/root/(: comment :) child[@attr]')
|
|
23
23
|
>>> isinstance(token, XPathToken)
|
|
24
24
|
True
|
|
25
|
+
|
|
26
|
+
That token is a proxy token for the tree produced by TDOP parsing:
|
|
27
|
+
|
|
28
|
+
.. doctest::
|
|
29
|
+
|
|
25
30
|
>>> token
|
|
26
31
|
<_SolidusOperator object at 0x...
|
|
27
32
|
>>> str(token)
|
|
@@ -73,7 +78,7 @@ represented by *XPathContext* objects.
|
|
|
73
78
|
>>> root = ElementTree.XML('<root><child/><child attr="10"/></root>')
|
|
74
79
|
>>> context = XPathContext(root)
|
|
75
80
|
>>> token.evaluate(context)
|
|
76
|
-
[
|
|
81
|
+
[EtreeElementNode(elem=<Element 'child' at ...)]
|
|
77
82
|
|
|
78
83
|
In this case an error is raised if you don't provide a context:
|
|
79
84
|
|
|
@@ -124,9 +129,9 @@ Node trees are automatically created at dynamic context initialization:
|
|
|
124
129
|
>>> root = ElementTree.XML('<root><child/><child attr="10"/></root>')
|
|
125
130
|
>>> context = XPathContext(root)
|
|
126
131
|
>>> context.root
|
|
127
|
-
|
|
132
|
+
EtreeElementNode(elem=<Element 'root' at ...>)
|
|
128
133
|
>>> context.root.children
|
|
129
|
-
[
|
|
134
|
+
[EtreeElementNode(elem=<Element 'child' at ...>), EtreeElementNode(elem=<Element 'child' at ...>)]
|
|
130
135
|
|
|
131
136
|
If the same XML data is applied several times for dynamic evaluation it maybe
|
|
132
137
|
convenient to build the node tree before, in the way to create it only once:
|
|
@@ -232,7 +237,7 @@ context item is set to context root:
|
|
|
232
237
|
|
|
233
238
|
>>> context = XPathContext(doc)
|
|
234
239
|
>>> context.root
|
|
235
|
-
|
|
240
|
+
EtreeDocumentNode(document=<xml.etree.ElementTree.ElementTree object at ...>)
|
|
236
241
|
>>> context.item is context.root
|
|
237
242
|
True
|
|
238
243
|
>>> context.document is context.root
|
|
@@ -246,11 +251,11 @@ set to root element node. In this case the context document is a dummy document:
|
|
|
246
251
|
>>> root = ElementTree.XML('<root><child1/><child2/><child3/></root>')
|
|
247
252
|
>>> context = XPathContext(root)
|
|
248
253
|
>>> context.root
|
|
249
|
-
|
|
254
|
+
EtreeElementNode(elem=<Element 'root' at ...>)
|
|
250
255
|
>>> context.item is context.root
|
|
251
256
|
True
|
|
252
257
|
>>> context.document
|
|
253
|
-
|
|
258
|
+
EtreeDocumentNode(document=<xml.etree.ElementTree.ElementTree object at ...>)
|
|
254
259
|
>>> context.root.parent is None
|
|
255
260
|
True
|
|
256
261
|
|
|
@@ -263,7 +268,7 @@ the data with lxml:
|
|
|
263
268
|
>>> root = etree.XML('<!-- comment --><root><child/></root>')
|
|
264
269
|
>>> context = XPathContext(root)
|
|
265
270
|
>>> context.root
|
|
266
|
-
|
|
271
|
+
EtreeDocumentNode(document=<lxml.etree._ElementTree object at ...>)
|
|
267
272
|
>>> context.item is context.root
|
|
268
273
|
True
|
|
269
274
|
>>> context.document is context.root
|
|
@@ -278,7 +283,7 @@ is set to `None`:
|
|
|
278
283
|
>>> root = ElementTree.XML('<root><child1/><child2/><child3/></root>')
|
|
279
284
|
>>> context = XPathContext(root, fragment=True)
|
|
280
285
|
>>> context.root
|
|
281
|
-
|
|
286
|
+
EtreeElementNode(elem=<Element 'root' at ...>)
|
|
282
287
|
>>> context.item is context.root
|
|
283
288
|
True
|
|
284
289
|
>>> context.document is None
|
|
@@ -25,13 +25,13 @@ sys.path.insert(0, os.path.abspath('..'))
|
|
|
25
25
|
# -- Project information -----------------------------------------------------
|
|
26
26
|
|
|
27
27
|
project = 'elementpath'
|
|
28
|
-
copyright = '2018-
|
|
28
|
+
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.
|
|
32
|
+
version = '4.8'
|
|
33
33
|
# The full version, including alpha/beta/rc tags
|
|
34
|
-
release = '4.
|
|
34
|
+
release = '4.8.0'
|
|
35
35
|
|
|
36
36
|
# -- General configuration ---------------------------------------------------
|
|
37
37
|
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
#
|
|
8
8
|
# @author Davide Brunato <brunato@sissa.it>
|
|
9
9
|
#
|
|
10
|
-
__version__ = '4.
|
|
10
|
+
__version__ = '4.8.0'
|
|
11
11
|
__author__ = "Davide Brunato"
|
|
12
12
|
__contact__ = "brunato@sissa.it"
|
|
13
|
-
__copyright__ = "Copyright 2018-
|
|
13
|
+
__copyright__ = "Copyright 2018-2025, SISSA"
|
|
14
14
|
__license__ = "MIT"
|
|
15
15
|
__status__ = "Production/Stable"
|
|
16
16
|
|
|
@@ -26,9 +26,9 @@ from .exceptions import ElementPathError, MissingContextError, ElementPathKeyErr
|
|
|
26
26
|
ElementPathValueError, ElementPathLocaleError, UnsupportedFeatureError
|
|
27
27
|
|
|
28
28
|
from .xpath_context import XPathContext, XPathSchemaContext
|
|
29
|
-
from .xpath_nodes import XPathNode,
|
|
30
|
-
|
|
31
|
-
|
|
29
|
+
from .xpath_nodes import XPathNode, AttributeNode, NamespaceNode, CommentNode, \
|
|
30
|
+
ProcessingInstructionNode, TextNode, ElementNode, LazyElementNode, \
|
|
31
|
+
SchemaElementNode, DocumentNode
|
|
32
32
|
from .tree_builders import get_node_tree, build_node_tree, build_lxml_node_tree, \
|
|
33
33
|
build_schema_node_tree
|
|
34
34
|
from .xpath_tokens import XPathToken, XPathFunction
|
|
@@ -39,15 +39,14 @@ from .schema_proxy import AbstractSchemaProxy
|
|
|
39
39
|
from .regex import RegexError, translate_pattern, install_unicode_data, unicode_version
|
|
40
40
|
|
|
41
41
|
__all__ = ['datatypes', 'protocols', 'etree', 'ElementPathError', 'MissingContextError',
|
|
42
|
-
'UnsupportedFeatureError', 'ElementPathKeyError',
|
|
42
|
+
'UnsupportedFeatureError', 'ElementPathKeyError', 'ElementPathLocaleError',
|
|
43
43
|
'ElementPathZeroDivisionError', 'ElementPathNameError',
|
|
44
44
|
'ElementPathOverflowError', 'ElementPathRuntimeError', 'ElementPathSyntaxError',
|
|
45
|
-
'ElementPathTypeError', 'ElementPathValueError', '
|
|
46
|
-
'
|
|
47
|
-
'
|
|
48
|
-
'
|
|
49
|
-
'
|
|
50
|
-
'build_lxml_node_tree', 'build_schema_node_tree', 'XPathToken',
|
|
45
|
+
'ElementPathTypeError', 'ElementPathValueError', 'XPathContext',
|
|
46
|
+
'XPathSchemaContext', 'XPathNode', 'AttributeNode', 'NamespaceNode',
|
|
47
|
+
'CommentNode', 'ProcessingInstructionNode', 'TextNode', 'ElementNode',
|
|
48
|
+
'LazyElementNode', 'SchemaElementNode', 'DocumentNode', 'get_node_tree',
|
|
49
|
+
'build_node_tree', 'build_lxml_node_tree', 'build_schema_node_tree', 'XPathToken',
|
|
51
50
|
'XPathFunction', 'XPath1Parser', 'XPath2Parser', 'select', 'iter_select',
|
|
52
51
|
'Selector', 'AbstractSchemaProxy', 'RegexError', 'translate_pattern',
|
|
53
52
|
'install_unicode_data', 'unicode_version']
|
|
@@ -30,8 +30,7 @@ InputType = Union[None, T, List[T], Tuple[T, ...]]
|
|
|
30
30
|
|
|
31
31
|
if TYPE_CHECKING:
|
|
32
32
|
from elementpath.datatypes import AtomicType, ArithmeticType, NumericType
|
|
33
|
-
from elementpath.xpath_nodes import ChildNodeType, ParentNodeType
|
|
34
|
-
from elementpath.tree_builders import RootArgType
|
|
33
|
+
from elementpath.xpath_nodes import ChildNodeType, ParentNodeType, RootArgType
|
|
35
34
|
from elementpath.xpath_context import ContextType, FunctionArgType, ItemType, \
|
|
36
35
|
ItemArgType, ValueType
|
|
37
36
|
from elementpath.xpath_tokens import XPathParserType, XPathTokenType
|
|
@@ -18,8 +18,8 @@ from elementpath.protocols import ElementProtocol
|
|
|
18
18
|
from elementpath.exceptions import xpath_error
|
|
19
19
|
from elementpath.datatypes import UntypedAtomic, AnyURI, AbstractQName
|
|
20
20
|
from elementpath.collations import UNICODE_CODEPOINT_COLLATION, CollationManager
|
|
21
|
-
from elementpath.xpath_nodes import XPathNode,
|
|
22
|
-
NamespaceNode, TextNode, CommentNode, ProcessingInstructionNode,
|
|
21
|
+
from elementpath.xpath_nodes import XPathNode, EtreeElementNode, TextAttributeNode, \
|
|
22
|
+
NamespaceNode, TextNode, CommentNode, ProcessingInstructionNode, EtreeDocumentNode
|
|
23
23
|
from elementpath.xpath_tokens import XPathToken, XPathFunction, XPathMap, XPathArray
|
|
24
24
|
|
|
25
25
|
|
|
@@ -28,7 +28,7 @@ def deep_equal(seq1: Iterable[Any],
|
|
|
28
28
|
collation: Optional[str] = None,
|
|
29
29
|
token: Optional[XPathToken] = None) -> bool:
|
|
30
30
|
|
|
31
|
-
etree_node_types = (
|
|
31
|
+
etree_node_types = (EtreeElementNode, CommentNode, ProcessingInstructionNode)
|
|
32
32
|
|
|
33
33
|
def etree_deep_equal(e1: ElementProtocol, e2: ElementProtocol) -> bool:
|
|
34
34
|
if cm.ne(e1.tag, e2.tag):
|
|
@@ -72,31 +72,31 @@ def deep_equal(seq1: Iterable[Any],
|
|
|
72
72
|
return False
|
|
73
73
|
elif isinstance(value1, XPathNode):
|
|
74
74
|
assert isinstance(value2, XPathNode)
|
|
75
|
-
if value1.
|
|
75
|
+
if value1.__class__ != value2.__class__:
|
|
76
76
|
return False
|
|
77
77
|
elif isinstance(value1, etree_node_types):
|
|
78
78
|
assert isinstance(value2, etree_node_types)
|
|
79
|
-
if not etree_deep_equal(value1.
|
|
79
|
+
if not etree_deep_equal(value1.obj, value2.obj):
|
|
80
80
|
return False
|
|
81
|
-
elif isinstance(value1,
|
|
82
|
-
assert isinstance(value2,
|
|
81
|
+
elif isinstance(value1, EtreeDocumentNode):
|
|
82
|
+
assert isinstance(value2, EtreeDocumentNode)
|
|
83
83
|
for child1, child2 in zip_longest(value1, value2):
|
|
84
84
|
if child1 is None or child2 is None:
|
|
85
85
|
return False
|
|
86
|
-
elif child1.
|
|
86
|
+
elif child1.__class__ != child2.__class__:
|
|
87
87
|
return False
|
|
88
88
|
elif isinstance(child1, etree_node_types):
|
|
89
89
|
assert isinstance(child2, etree_node_types)
|
|
90
|
-
if not etree_deep_equal(child1.
|
|
90
|
+
if not etree_deep_equal(child1.obj, child2.obj):
|
|
91
91
|
return False
|
|
92
92
|
elif isinstance(child1, TextNode):
|
|
93
93
|
assert isinstance(child2, TextNode)
|
|
94
|
-
if cm.ne(child1.
|
|
94
|
+
if cm.ne(child1.obj, child2.obj):
|
|
95
95
|
return False
|
|
96
96
|
|
|
97
|
-
elif cm.ne(value1.
|
|
97
|
+
elif cm.ne(value1.obj, value2.obj):
|
|
98
98
|
return False
|
|
99
|
-
elif isinstance(value1,
|
|
99
|
+
elif isinstance(value1, TextAttributeNode):
|
|
100
100
|
if cm.ne(value1.name, value2.name):
|
|
101
101
|
return False
|
|
102
102
|
elif isinstance(value1, NamespaceNode):
|
|
@@ -174,7 +174,7 @@ def deep_compare(obj1: Any,
|
|
|
174
174
|
token: Optional[XPathToken] = None) -> int:
|
|
175
175
|
|
|
176
176
|
msg_tmpl = "Sorting failed, cannot compare {!r} with {!r}"
|
|
177
|
-
etree_node_types = (
|
|
177
|
+
etree_node_types = (EtreeElementNode, CommentNode, ProcessingInstructionNode)
|
|
178
178
|
result: int = 0
|
|
179
179
|
|
|
180
180
|
def iter_object(obj: Any) -> Iterator[Any]:
|
|
@@ -244,51 +244,51 @@ def deep_compare(obj1: Any,
|
|
|
244
244
|
raise xpath_error('XPTY0004', msg, token=token)
|
|
245
245
|
elif isinstance(value1, XPathNode):
|
|
246
246
|
assert isinstance(value2, XPathNode)
|
|
247
|
-
if value1.
|
|
247
|
+
if value1.__class__ != value2.__class__:
|
|
248
248
|
msg = f"cannot compare {type(value1)} with {type(value2)}"
|
|
249
249
|
raise xpath_error('XPTY0004', msg, token=token)
|
|
250
250
|
elif isinstance(value1, etree_node_types):
|
|
251
251
|
assert isinstance(value2, etree_node_types)
|
|
252
|
-
result = etree_deep_compare(value1.
|
|
252
|
+
result = etree_deep_compare(value1.obj, value2.obj)
|
|
253
253
|
if result:
|
|
254
254
|
return result
|
|
255
|
-
elif isinstance(value1,
|
|
256
|
-
assert isinstance(value2,
|
|
255
|
+
elif isinstance(value1, EtreeDocumentNode):
|
|
256
|
+
assert isinstance(value2, EtreeDocumentNode)
|
|
257
257
|
for child1, child2 in zip_longest(value1, value2):
|
|
258
258
|
if child1 is None:
|
|
259
259
|
return -1
|
|
260
260
|
elif child2 is None:
|
|
261
261
|
return 1
|
|
262
|
-
elif child1.
|
|
262
|
+
elif child1.__class__ != child2.__class__:
|
|
263
263
|
msg = f"cannot compare {type(child1)} with {type(child2)}"
|
|
264
264
|
raise xpath_error('XPTY0004', msg, token=token)
|
|
265
265
|
elif isinstance(child1, etree_node_types):
|
|
266
266
|
assert isinstance(child2, etree_node_types)
|
|
267
|
-
result = etree_deep_compare(child1.
|
|
267
|
+
result = etree_deep_compare(child1.obj, child2.obj)
|
|
268
268
|
if result:
|
|
269
269
|
return result
|
|
270
270
|
elif isinstance(child1, TextNode):
|
|
271
271
|
assert isinstance(child2, TextNode)
|
|
272
272
|
result = cm.strcoll(
|
|
273
|
-
child1.
|
|
273
|
+
child1.obj.strip(), child2.obj.strip()
|
|
274
274
|
)
|
|
275
275
|
if result:
|
|
276
276
|
return result
|
|
277
|
-
|
|
278
|
-
|
|
277
|
+
elif isinstance(value1, TextNode):
|
|
278
|
+
assert isinstance(value2, TextNode)
|
|
279
|
+
result = cm.strcoll(value1.obj, value2.obj)
|
|
280
|
+
if result:
|
|
281
|
+
return result
|
|
282
|
+
elif isinstance(value1, TextAttributeNode):
|
|
283
|
+
assert isinstance(value2, TextAttributeNode)
|
|
284
|
+
result = cm.strcoll(value1.name or '', value2.name or '')
|
|
285
|
+
if result:
|
|
286
|
+
return result
|
|
287
|
+
elif isinstance(value1, NamespaceNode):
|
|
288
|
+
assert isinstance(value2, NamespaceNode)
|
|
289
|
+
result = cm.strcoll(value1.prefix or '', value2.prefix or '')
|
|
279
290
|
if result:
|
|
280
291
|
return result
|
|
281
|
-
|
|
282
|
-
if isinstance(value1, AttributeNode):
|
|
283
|
-
assert isinstance(value2, AttributeNode)
|
|
284
|
-
result = cm.strcoll(value1.name or '', value2.name or '')
|
|
285
|
-
if result:
|
|
286
|
-
return result
|
|
287
|
-
elif isinstance(value1, NamespaceNode):
|
|
288
|
-
assert isinstance(value2, NamespaceNode)
|
|
289
|
-
result = cm.strcoll(value1.prefix or '', value2.prefix or '')
|
|
290
|
-
if result:
|
|
291
|
-
return result
|
|
292
292
|
else:
|
|
293
293
|
try:
|
|
294
294
|
if isinstance(value1, bool):
|
|
@@ -131,8 +131,15 @@ class AbstractDateTime(AnyAtomicType):
|
|
|
131
131
|
tzinfo: Optional[datetime.tzinfo] = None) -> None:
|
|
132
132
|
|
|
133
133
|
if hour == 24 and minute == second == microsecond == 0:
|
|
134
|
-
delta = datetime.timedelta(days=1)
|
|
135
134
|
hour = 0
|
|
135
|
+
if year == 9999 and month == 12 and day == 31:
|
|
136
|
+
delta = datetime.timedelta(0)
|
|
137
|
+
year = 10000
|
|
138
|
+
month = 1
|
|
139
|
+
day = 1
|
|
140
|
+
else:
|
|
141
|
+
delta = datetime.timedelta(days=1)
|
|
142
|
+
hour = 0
|
|
136
143
|
else:
|
|
137
144
|
delta = datetime.timedelta(0)
|
|
138
145
|
|
|
@@ -169,7 +169,7 @@ class Integer(int, AnyAtomicType):
|
|
|
169
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
|
-
return NotImplemented
|
|
172
|
+
return NotImplemented # type: ignore[no-any-return,unused-ignore]
|
|
173
173
|
|
|
174
174
|
@classmethod
|
|
175
175
|
def validate(cls, value: object) -> None:
|
|
@@ -0,0 +1,170 @@
|
|
|
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
|
+
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 collections import namedtuple
|
|
16
|
+
from decimal import Decimal
|
|
17
|
+
from functools import lru_cache
|
|
18
|
+
from typing import List, Optional, Type
|
|
19
|
+
|
|
20
|
+
from elementpath._typing import Callable, Iterator, MutableMapping
|
|
21
|
+
from elementpath.aliases import AnyNsmapType
|
|
22
|
+
from elementpath.datatypes import AtomicType
|
|
23
|
+
from elementpath.protocols import XsdTypeProtocol
|
|
24
|
+
from elementpath.exceptions import xpath_error
|
|
25
|
+
from elementpath.namespaces import XSD_NAMESPACE
|
|
26
|
+
|
|
27
|
+
import elementpath.datatypes as dt
|
|
28
|
+
|
|
29
|
+
DecoderType = Callable[[str, AnyNsmapType], AtomicType]
|
|
30
|
+
|
|
31
|
+
Builder = namedtuple('Builder', 'cls text nsmap', defaults=(None, None))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class _Notation(dt.Notation):
|
|
35
|
+
"""An instantiable xs:NOTATION."""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
# noinspection PyArgumentList
|
|
39
|
+
ATOMIC_BUILDERS: MutableMapping[Optional[str], Builder] = {
|
|
40
|
+
f'{{{XSD_NAMESPACE}}}untypedAtomic': Builder(dt.UntypedAtomic, '1'),
|
|
41
|
+
f'{{{XSD_NAMESPACE}}}anyType': Builder(dt.UntypedAtomic, '1'),
|
|
42
|
+
f'{{{XSD_NAMESPACE}}}anySimpleType': Builder(dt.UntypedAtomic, '1'),
|
|
43
|
+
f'{{{XSD_NAMESPACE}}}anyAtomicType': Builder(dt.UntypedAtomic, '1'),
|
|
44
|
+
f'{{{XSD_NAMESPACE}}}boolean': Builder(bool, 'true'),
|
|
45
|
+
f'{{{XSD_NAMESPACE}}}decimal': Builder(Decimal, '1.0'),
|
|
46
|
+
f'{{{XSD_NAMESPACE}}}double': Builder(float, '1.0'),
|
|
47
|
+
f'{{{XSD_NAMESPACE}}}float': Builder(dt.Float10, '1.0'),
|
|
48
|
+
f'{{{XSD_NAMESPACE}}}string': Builder(str, ' alpha\t'),
|
|
49
|
+
f'{{{XSD_NAMESPACE}}}date': Builder(dt.Date, '2000-01-01'),
|
|
50
|
+
f'{{{XSD_NAMESPACE}}}dateTime': Builder(dt.DateTime, '2000-01-01T12:00:00'),
|
|
51
|
+
f'{{{XSD_NAMESPACE}}}gDay': Builder(dt.GregorianDay, '---31'),
|
|
52
|
+
f'{{{XSD_NAMESPACE}}}gMonth': Builder(dt.GregorianMonth, '--12'),
|
|
53
|
+
f'{{{XSD_NAMESPACE}}}gMonthDay': Builder(dt.GregorianMonthDay, '--12-01'),
|
|
54
|
+
f'{{{XSD_NAMESPACE}}}gYear': Builder(dt.GregorianYear, '1999'),
|
|
55
|
+
f'{{{XSD_NAMESPACE}}}gYearMonth': Builder(dt.GregorianYearMonth, '1999-09'),
|
|
56
|
+
f'{{{XSD_NAMESPACE}}}time': Builder(dt.Time, '09:26:54'),
|
|
57
|
+
f'{{{XSD_NAMESPACE}}}duration': Builder(dt.Duration, 'P1MT1S'),
|
|
58
|
+
f'{{{XSD_NAMESPACE}}}dayTimeDuration': Builder(dt.DayTimeDuration, 'P1DT1S'),
|
|
59
|
+
f'{{{XSD_NAMESPACE}}}yearMonthDuration': Builder(dt.YearMonthDuration, 'P1Y1M'),
|
|
60
|
+
f'{{{XSD_NAMESPACE}}}QName': Builder(dt.QName, 'xs:element'),
|
|
61
|
+
f'{{{XSD_NAMESPACE}}}NOTATION': Builder(_Notation, 'xs:element'),
|
|
62
|
+
f'{{{XSD_NAMESPACE}}}anyURI': Builder(dt.AnyURI, 'https://example.com'),
|
|
63
|
+
f'{{{XSD_NAMESPACE}}}normalizedString': Builder(dt.NormalizedString, ' alpha '),
|
|
64
|
+
f'{{{XSD_NAMESPACE}}}token': Builder(dt.XsdToken, 'a token'),
|
|
65
|
+
f'{{{XSD_NAMESPACE}}}language': Builder(dt.Language, 'en-US'),
|
|
66
|
+
f'{{{XSD_NAMESPACE}}}Name': Builder(dt.Name, '_a.name::'),
|
|
67
|
+
f'{{{XSD_NAMESPACE}}}NCName': Builder(dt.NCName, 'nc-name'),
|
|
68
|
+
f'{{{XSD_NAMESPACE}}}ID': Builder(dt.Id, 'id1'),
|
|
69
|
+
f'{{{XSD_NAMESPACE}}}IDREF': Builder(dt.Idref, 'id_ref1'),
|
|
70
|
+
f'{{{XSD_NAMESPACE}}}ENTITY': Builder(dt.Entity, 'entity1'),
|
|
71
|
+
f'{{{XSD_NAMESPACE}}}NMTOKEN': Builder(dt.NMToken, 'a_token'),
|
|
72
|
+
f'{{{XSD_NAMESPACE}}}base64Binary': Builder(dt.Base64Binary, 'YWxwaGE='),
|
|
73
|
+
f'{{{XSD_NAMESPACE}}}hexBinary': Builder(dt.HexBinary, '31'),
|
|
74
|
+
f'{{{XSD_NAMESPACE}}}dateTimeStamp':
|
|
75
|
+
Builder(dt.DateTimeStamp.fromstring, '2000-01-01T12:00:00+01:00'),
|
|
76
|
+
f'{{{XSD_NAMESPACE}}}integer': Builder(dt.Integer, '1'),
|
|
77
|
+
f'{{{XSD_NAMESPACE}}}long': Builder(dt.Long, '1'),
|
|
78
|
+
f'{{{XSD_NAMESPACE}}}int': Builder(dt.Int, '1'),
|
|
79
|
+
f'{{{XSD_NAMESPACE}}}short': Builder(dt.Short, '1'),
|
|
80
|
+
f'{{{XSD_NAMESPACE}}}byte': Builder(dt.Byte, '1'),
|
|
81
|
+
f'{{{XSD_NAMESPACE}}}positiveInteger': Builder(dt.PositiveInteger, '1'),
|
|
82
|
+
f'{{{XSD_NAMESPACE}}}negativeInteger': Builder(dt.NegativeInteger, '-1'),
|
|
83
|
+
f'{{{XSD_NAMESPACE}}}nonPositiveInteger': Builder(dt.NonPositiveInteger, '0'),
|
|
84
|
+
f'{{{XSD_NAMESPACE}}}nonNegativeInteger': Builder(dt.NonNegativeInteger, '0'),
|
|
85
|
+
f'{{{XSD_NAMESPACE}}}unsignedLong': Builder(dt.UnsignedLong, '1'),
|
|
86
|
+
f'{{{XSD_NAMESPACE}}}unsignedInt': Builder(dt.UnsignedInt, '1'),
|
|
87
|
+
f'{{{XSD_NAMESPACE}}}unsignedShort': Builder(dt.UnsignedShort, '1'),
|
|
88
|
+
f'{{{XSD_NAMESPACE}}}unsignedByte': Builder(dt.UnsignedByte, '1'),
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
@lru_cache(maxsize=None)
|
|
93
|
+
def get_builders(xsd_type: XsdTypeProtocol) -> List[Builder]:
|
|
94
|
+
"""
|
|
95
|
+
Returns a list of atomic builtin XSD types that are in the base type of
|
|
96
|
+
the XSD type argument.
|
|
97
|
+
"""
|
|
98
|
+
def iter_builders(root_type: XsdTypeProtocol, depth: int) -> Iterator[Builder]:
|
|
99
|
+
if depth > 15:
|
|
100
|
+
return
|
|
101
|
+
if root_type.name in ATOMIC_BUILDERS:
|
|
102
|
+
yield ATOMIC_BUILDERS[root_type.name]
|
|
103
|
+
elif hasattr(root_type, 'member_types'):
|
|
104
|
+
for member_type in root_type.member_types:
|
|
105
|
+
yield from iter_builders(member_type, depth + 1)
|
|
106
|
+
|
|
107
|
+
if xsd_type.name in ATOMIC_BUILDERS:
|
|
108
|
+
return [ATOMIC_BUILDERS[xsd_type.name]]
|
|
109
|
+
elif xsd_type.is_simple() or (simple_type := xsd_type.simple_type) is None:
|
|
110
|
+
return [builder for builder in iter_builders(xsd_type.root_type, 1)]
|
|
111
|
+
elif simple_type.name in ATOMIC_BUILDERS:
|
|
112
|
+
return [ATOMIC_BUILDERS[simple_type.name]]
|
|
113
|
+
return [builder for builder in iter_builders(simple_type.root_type, 1)]
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def get_atomic_sequence(xsd_type: Optional[XsdTypeProtocol],
|
|
117
|
+
text: object = None,
|
|
118
|
+
namespaces: AnyNsmapType = None) -> Iterator[dt.AtomicType]:
|
|
119
|
+
"""Returns a decoder function for atomic values of an XSD type instance."""
|
|
120
|
+
def decode(value: str) -> dt.AtomicType:
|
|
121
|
+
if issubclass(cls, (dt.AbstractDateTime, dt.Duration)):
|
|
122
|
+
return cls.fromstring(value)
|
|
123
|
+
elif not issubclass(cls, dt.AbstractQName):
|
|
124
|
+
return cls(value)
|
|
125
|
+
else:
|
|
126
|
+
nonlocal namespaces
|
|
127
|
+
if namespaces is None:
|
|
128
|
+
namespaces = {'xs': XSD_NAMESPACE}
|
|
129
|
+
if ':' not in value:
|
|
130
|
+
return cls(namespaces.get(''), value)
|
|
131
|
+
else:
|
|
132
|
+
return cls(namespaces[value.split(':')[0]], value)
|
|
133
|
+
|
|
134
|
+
if xsd_type is None:
|
|
135
|
+
yield dt.UntypedAtomic(text if isinstance(text, str) else '')
|
|
136
|
+
return
|
|
137
|
+
|
|
138
|
+
for k, builder in enumerate(get_builders(xsd_type), start=1):
|
|
139
|
+
cls: Type[dt.AtomicType] = builder.cls
|
|
140
|
+
|
|
141
|
+
_text = text if isinstance(text, str) else builder.text
|
|
142
|
+
if len(builder) < k and not xsd_type.is_valid(text, namespaces=namespaces):
|
|
143
|
+
continue
|
|
144
|
+
|
|
145
|
+
try:
|
|
146
|
+
if xsd_type.is_list():
|
|
147
|
+
for item in _text.split():
|
|
148
|
+
yield decode(item)
|
|
149
|
+
else:
|
|
150
|
+
yield decode(_text)
|
|
151
|
+
|
|
152
|
+
except ValueError as err:
|
|
153
|
+
raise xpath_error('FORG0001', err, namespaces=namespaces)
|
|
154
|
+
except ArithmeticError as err:
|
|
155
|
+
if issubclass(cls, dt.AbstractDateTime):
|
|
156
|
+
raise xpath_error('FODT0001', err, namespaces=namespaces)
|
|
157
|
+
elif issubclass(cls, dt.Duration):
|
|
158
|
+
raise xpath_error('FODT0002', err, namespaces=namespaces)
|
|
159
|
+
else:
|
|
160
|
+
raise xpath_error('FOCA0002', err, namespaces=namespaces)
|
|
161
|
+
else:
|
|
162
|
+
return
|
|
163
|
+
else:
|
|
164
|
+
if hasattr(xsd_type, 'decode'):
|
|
165
|
+
yield xsd_type.decode(text if isinstance(text, str) else '')
|
|
166
|
+
else:
|
|
167
|
+
yield dt.UntypedAtomic(text if isinstance(text, str) else '')
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
__all__ = ['ATOMIC_BUILDERS', 'get_atomic_sequence']
|
|
@@ -106,7 +106,17 @@ def is_etree_element(obj: Any) -> bool:
|
|
|
106
106
|
|
|
107
107
|
|
|
108
108
|
def is_lxml_etree_element(obj: Any) -> bool:
|
|
109
|
-
return is_etree_element(obj) and
|
|
109
|
+
return is_etree_element(obj) and \
|
|
110
|
+
hasattr(obj, 'getparent') and \
|
|
111
|
+
hasattr(obj, 'nsmap') and \
|
|
112
|
+
obj.__class__.__module__ in ('lxml.etree', 'lxml.html')
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def is_etree_element_instance(obj: Any) -> bool:
|
|
116
|
+
"""Strictly checks that the objects is an ElementTree or lxml.etree Element."""
|
|
117
|
+
return isinstance(obj, ElementTree.Element) or \
|
|
118
|
+
isinstance(obj, PyElementTree.Element) or \
|
|
119
|
+
is_lxml_etree_element(obj)
|
|
110
120
|
|
|
111
121
|
|
|
112
122
|
def is_etree_document(obj: Any) -> bool:
|
|
@@ -114,7 +124,17 @@ def is_etree_document(obj: Any) -> bool:
|
|
|
114
124
|
|
|
115
125
|
|
|
116
126
|
def is_lxml_etree_document(obj: Any) -> bool:
|
|
117
|
-
return is_etree_document(obj) and
|
|
127
|
+
return is_etree_document(obj) and \
|
|
128
|
+
hasattr(obj, 'xpath') and \
|
|
129
|
+
hasattr(obj, 'xslt') and \
|
|
130
|
+
obj.__class__.__module__ in ('lxml.etree', 'lxml.html')
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def is_etree_document_instance(obj: Any) -> bool:
|
|
134
|
+
"""Strictly checks that the objects is an ElementTree or lxml.etree document."""
|
|
135
|
+
return isinstance(obj, ElementTree.ElementTree) or \
|
|
136
|
+
isinstance(obj, PyElementTree.ElementTree) or \
|
|
137
|
+
is_lxml_etree_document(obj)
|
|
118
138
|
|
|
119
139
|
|
|
120
140
|
def etree_iter_strings(elem: Union[DocumentProtocol, ElementProtocol],
|
|
@@ -237,7 +257,7 @@ def etree_tostring(elem: ElementProtocol,
|
|
|
237
257
|
return indent + line
|
|
238
258
|
|
|
239
259
|
etree_module: Any
|
|
240
|
-
if not
|
|
260
|
+
if not is_etree_element_instance(elem):
|
|
241
261
|
raise TypeError(f"{elem!r} is not an Element")
|
|
242
262
|
elif isinstance(elem, PyElementTree.Element):
|
|
243
263
|
etree_module = PyElementTree
|
|
@@ -308,6 +328,6 @@ def etree_tostring(elem: ElementProtocol,
|
|
|
308
328
|
|
|
309
329
|
|
|
310
330
|
__all__ = ['ElementTree', 'PyElementTree', 'SafeXMLParser', 'defuse_xml',
|
|
311
|
-
'is_etree_element', 'is_lxml_etree_element', '
|
|
312
|
-
'
|
|
313
|
-
'etree_iter_paths', 'etree_tostring']
|
|
331
|
+
'is_etree_element', 'is_lxml_etree_element', 'is_etree_element_instance',
|
|
332
|
+
'is_etree_document', 'is_lxml_etree_document', 'is_etree_document_instance',
|
|
333
|
+
'etree_iter_strings', 'etree_deep_equal', 'etree_iter_paths', 'etree_tostring']
|