elementpath 4.1.5__tar.gz → 4.2.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.1.5 → elementpath-4.2.0}/CHANGELOG.rst +8 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/PKG-INFO +13 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/advanced.rst +41 -5
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/conf.py +3 -3
- elementpath-4.2.0/doc/requirements.txt +2 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/__init__.py +2 -2
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/compare.py +4 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/atomic_types.py +4 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/helpers.py +14 -2
- elementpath-4.2.0/elementpath/protocols.py +178 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/tdop.py +4 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/tree_builders.py +75 -28
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_functions.py +4 -11
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_operators.py +6 -6
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath1/xpath1_parser.py +37 -1
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_functions.py +2 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_operators.py +4 -8
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/_xpath30_functions.py +4 -28
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath_context.py +209 -198
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath_nodes.py +99 -62
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath_tokens.py +69 -61
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath.egg-info/PKG-INFO +13 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath.egg-info/SOURCES.txt +1 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/setup.py +2 -3
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/execute_w3c_tests.py +1 -1
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_package.py +37 -2
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_validators.py +7 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath1_parser.py +35 -4
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath2_functions.py +12 -3
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath2_parser.py +1 -1
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath30.py +2 -1
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath_context.py +106 -2
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath_nodes.py +40 -5
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath_tokens.py +1 -1
- {elementpath-4.1.5 → elementpath-4.2.0}/tox.ini +27 -13
- elementpath-4.1.5/elementpath/protocols.py +0 -184
- {elementpath-4.1.5 → elementpath-4.2.0}/.coveragerc +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/LICENSE +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/MANIFEST.in +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/README.rst +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/Makefile +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/index.rst +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/introduction.rst +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/make.bat +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/pratt_api.rst +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/doc/xpath_api.rst +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/collations.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/binary.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/datetime.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/numeric.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/proxies.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/qname.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/string.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/untyped.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/datatypes/uri.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/etree.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/exceptions.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/namespaces.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/py.typed +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/character_classes.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/codepoints.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/generate_categories.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/patterns.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/unicode_categories.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/regex/unicode_subsets.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/schema_proxy.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/sequence_types.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/serialization.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/validators/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/validators/analyze-string.xsd +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/validators/schema-for-json.xsd +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath1/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_axes.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath2/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_constructors.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath2/xpath2_parser.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath3.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/_translation_maps.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/_xpath30_operators.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/xpath30_helpers.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath30/xpath30_parser.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath31/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath31/_xpath31_functions.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath31/_xpath31_operators.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath31/xpath31_parser.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath/xpath_selectors.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath.egg-info/dependency_links.txt +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath.egg-info/requires.txt +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/elementpath.egg-info/top_level.txt +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/mypy.ini +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/requirements-dev.txt +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/setup.cfg +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/__init__.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/memory_profiling.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/mypy_tests/selectors.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/analyze-string.xsd +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/external_entity.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/sample.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/schema-for-json.xsd +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/unparsed_entity.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/unused_external_entity.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/unused_unparsed_entity.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/resources/with_entity.xml +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_collations.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_compare.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_datatypes.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_elementpath.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_etree.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_exceptions.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_helpers.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_namespaces.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_regex.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_schema_context.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_schema_proxy.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_selectors.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_sequence_types.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_serialization.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_tdop_parser.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_tree_builders.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_typing.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath2_constructors.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/test_xpath31.py +0 -0
- {elementpath-4.1.5 → elementpath-4.2.0}/tests/xpath_test_class.py +0 -0
|
@@ -2,6 +2,13 @@
|
|
|
2
2
|
CHANGELOG
|
|
3
3
|
*********
|
|
4
4
|
|
|
5
|
+
`v4.2.0`_ (2024-02-03)
|
|
6
|
+
======================
|
|
7
|
+
* Drop support for Python 3.7
|
|
8
|
+
* Add *uri* and *fragment* options to dynamic context
|
|
9
|
+
* Make context root node not mandatory (issue #63)
|
|
10
|
+
* Add function objects constructor (issue #70)
|
|
11
|
+
|
|
5
12
|
`v4.1.5`_ (2023-07-25)
|
|
6
13
|
======================
|
|
7
14
|
* Fix typed value of ElementNode() if self.elem.text is None
|
|
@@ -435,3 +442,4 @@ CHANGELOG
|
|
|
435
442
|
.. _v4.1.3: https://github.com/sissaschool/elementpath/compare/v4.1.2...v4.1.3
|
|
436
443
|
.. _v4.1.4: https://github.com/sissaschool/elementpath/compare/v4.1.3...v4.1.4
|
|
437
444
|
.. _v4.1.5: https://github.com/sissaschool/elementpath/compare/v4.1.4...v4.1.5
|
|
445
|
+
.. _v4.2.0: https://github.com/sissaschool/elementpath/compare/v4.1.5...v4.2.0
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.1
|
|
2
2
|
Name: elementpath
|
|
3
|
-
Version: 4.
|
|
3
|
+
Version: 4.2.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
|
|
@@ -16,7 +16,6 @@ Classifier: Operating System :: OS Independent
|
|
|
16
16
|
Classifier: Programming Language :: Python
|
|
17
17
|
Classifier: Programming Language :: Python :: 3
|
|
18
18
|
Classifier: Programming Language :: Python :: 3 :: Only
|
|
19
|
-
Classifier: Programming Language :: Python :: 3.7
|
|
20
19
|
Classifier: Programming Language :: Python :: 3.8
|
|
21
20
|
Classifier: Programming Language :: Python :: 3.9
|
|
22
21
|
Classifier: Programming Language :: Python :: 3.10
|
|
@@ -26,9 +25,19 @@ Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
|
26
25
|
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
27
26
|
Classifier: Topic :: Software Development :: Libraries
|
|
28
27
|
Classifier: Topic :: Text Processing :: Markup :: XML
|
|
29
|
-
Requires-Python: >=3.
|
|
30
|
-
Provides-Extra: dev
|
|
28
|
+
Requires-Python: >=3.8
|
|
31
29
|
License-File: LICENSE
|
|
30
|
+
Provides-Extra: dev
|
|
31
|
+
Requires-Dist: tox; extra == "dev"
|
|
32
|
+
Requires-Dist: coverage; extra == "dev"
|
|
33
|
+
Requires-Dist: lxml; extra == "dev"
|
|
34
|
+
Requires-Dist: xmlschema>=2.0.0; extra == "dev"
|
|
35
|
+
Requires-Dist: Sphinx; extra == "dev"
|
|
36
|
+
Requires-Dist: memory-profiler; extra == "dev"
|
|
37
|
+
Requires-Dist: memray; extra == "dev"
|
|
38
|
+
Requires-Dist: flake8; extra == "dev"
|
|
39
|
+
Requires-Dist: mypy; extra == "dev"
|
|
40
|
+
Requires-Dist: lxml-stubs; extra == "dev"
|
|
32
41
|
|
|
33
42
|
***********
|
|
34
43
|
elementpath
|
|
@@ -194,10 +194,24 @@ done using a subtree of nodes:
|
|
|
194
194
|
Both choices can be useful, depends if you need to keep the whole tree or
|
|
195
195
|
to restrict the scope to a subtree.
|
|
196
196
|
|
|
197
|
+
The context *item* can be set with an XPath node, an atomic value or an XPath function.
|
|
198
|
+
|
|
199
|
+
.. note::
|
|
200
|
+
Since release v4.2.0 the *root* is optional. If the argument *root* is absent
|
|
201
|
+
the argument *item* is mandatory and the dynamic context remain without a root.
|
|
202
|
+
|
|
197
203
|
|
|
198
204
|
The root document and the root element
|
|
199
205
|
======================================
|
|
200
206
|
|
|
207
|
+
.. warning::
|
|
208
|
+
The initialization of context root and item is changed in release v4.2.0.
|
|
209
|
+
|
|
210
|
+
Since then the provided XML is still considered a document for default, but the
|
|
211
|
+
item is set with the root instead of `None` and the new attribute *document* is
|
|
212
|
+
set with a dummy document for handling the document position. The dummy document
|
|
213
|
+
is not referred by the root element and is discarded from results.
|
|
214
|
+
|
|
201
215
|
Canonically the dynamic evaluation is performed on an XML document, created
|
|
202
216
|
from an ElementTree instance:
|
|
203
217
|
|
|
@@ -212,18 +226,20 @@ from an ElementTree instance:
|
|
|
212
226
|
<xml.etree.ElementTree.ElementTree object at ...>
|
|
213
227
|
|
|
214
228
|
In this case a document node is created at context initialization and the
|
|
215
|
-
context item is
|
|
229
|
+
context item is set to context root:
|
|
216
230
|
|
|
217
231
|
.. doctest::
|
|
218
232
|
|
|
219
233
|
>>> context = XPathContext(doc)
|
|
220
234
|
>>> context.root
|
|
221
235
|
DocumentNode(document=<xml.etree.ElementTree.ElementTree object at ...>)
|
|
222
|
-
>>> context.item is
|
|
236
|
+
>>> context.item is context.root
|
|
237
|
+
True
|
|
238
|
+
>>> context.document is context.root
|
|
223
239
|
True
|
|
224
240
|
|
|
225
241
|
Providing a root element the document is not created and the context item is
|
|
226
|
-
set to root element node:
|
|
242
|
+
set to root element node. In this case the context document is a dummy document:
|
|
227
243
|
|
|
228
244
|
.. doctest::
|
|
229
245
|
|
|
@@ -233,6 +249,10 @@ set to root element node:
|
|
|
233
249
|
ElementNode(elem=<Element 'root' at ...>)
|
|
234
250
|
>>> context.item is context.root
|
|
235
251
|
True
|
|
252
|
+
>>> context.document
|
|
253
|
+
DocumentNode(document=<xml.etree.ElementTree.ElementTree object at ...>)
|
|
254
|
+
>>> context.root.parent is None
|
|
255
|
+
True
|
|
236
256
|
|
|
237
257
|
Exception to this is if XML data root has siblings and if you process
|
|
238
258
|
the data with lxml:
|
|
@@ -244,6 +264,22 @@ the data with lxml:
|
|
|
244
264
|
>>> context = XPathContext(root)
|
|
245
265
|
>>> context.root
|
|
246
266
|
DocumentNode(document=<lxml.etree._ElementTree object at ...>)
|
|
247
|
-
>>> context.item
|
|
248
|
-
|
|
267
|
+
>>> context.item is context.root
|
|
268
|
+
True
|
|
269
|
+
>>> context.document is context.root
|
|
270
|
+
True
|
|
271
|
+
|
|
272
|
+
Provide the option *fragment* with value `True` for processing an XML root element
|
|
273
|
+
as a fragment. In this case a dummy document is not created and the context document
|
|
274
|
+
is set to `None`:
|
|
249
275
|
|
|
276
|
+
.. doctest::
|
|
277
|
+
|
|
278
|
+
>>> root = ElementTree.XML('<root><child1/><child2/><child3/></root>')
|
|
279
|
+
>>> context = XPathContext(root, fragment=True)
|
|
280
|
+
>>> context.root
|
|
281
|
+
ElementNode(elem=<Element 'root' at ...>)
|
|
282
|
+
>>> context.item is context.root
|
|
283
|
+
True
|
|
284
|
+
>>> context.document is None
|
|
285
|
+
True
|
|
@@ -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-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.2'
|
|
33
33
|
# The full version, including alpha/beta/rc tags
|
|
34
|
-
release = '4.
|
|
34
|
+
release = '4.2.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.2.0'
|
|
11
11
|
__author__ = "Davide Brunato"
|
|
12
12
|
__contact__ = "brunato@sissa.it"
|
|
13
|
-
__copyright__ = "Copyright 2018-
|
|
13
|
+
__copyright__ = "Copyright 2018-2024, SISSA"
|
|
14
14
|
__license__ = "MIT"
|
|
15
15
|
__status__ = "Production/Stable"
|
|
16
16
|
|
|
@@ -308,11 +308,11 @@ def deep_compare(obj1: Any,
|
|
|
308
308
|
|
|
309
309
|
elif isinstance(value1, float):
|
|
310
310
|
if math.isnan(value1):
|
|
311
|
-
if not math.isnan(value2):
|
|
311
|
+
if not math.isnan(value2):
|
|
312
312
|
return -1
|
|
313
313
|
elif math.isinf(value1):
|
|
314
314
|
if value1 != value2:
|
|
315
|
-
return -1 if value1 < value2 else 1
|
|
315
|
+
return -1 if value1 < value2 else 1
|
|
316
316
|
elif isinstance(value2, Decimal):
|
|
317
317
|
if value1 != float(value2):
|
|
318
318
|
return -1 if value1 < float(value2) else 1
|
|
@@ -326,7 +326,7 @@ def deep_compare(obj1: Any,
|
|
|
326
326
|
return -1
|
|
327
327
|
elif math.isinf(value2):
|
|
328
328
|
if value1 != value2:
|
|
329
|
-
return -1 if value1 < value2 else 1
|
|
329
|
+
return -1 if value1 < value2 else 1
|
|
330
330
|
elif isinstance(value1, Decimal):
|
|
331
331
|
if value2 != float(value1):
|
|
332
332
|
return -1 if float(value1) < value2 else 1
|
|
@@ -341,7 +341,7 @@ def deep_compare(obj1: Any,
|
|
|
341
341
|
if result:
|
|
342
342
|
return result
|
|
343
343
|
elif value1 != value2:
|
|
344
|
-
return -1 if value1 < value2 else 1
|
|
344
|
+
return -1 if value1 < value2 else 1
|
|
345
345
|
|
|
346
346
|
except TypeError as err:
|
|
347
347
|
raise xpath_error('XPTY0004', message_or_error=err, token=token)
|
|
@@ -68,7 +68,7 @@ class AtomicTypeMeta(ABCMeta):
|
|
|
68
68
|
|
|
69
69
|
return cls
|
|
70
70
|
|
|
71
|
-
def validate(cls, value: object) -> None:
|
|
71
|
+
def validate(cls: Type[Any], value: object) -> None:
|
|
72
72
|
if isinstance(value, cls):
|
|
73
73
|
return
|
|
74
74
|
elif isinstance(value, str):
|
|
@@ -77,7 +77,7 @@ class AtomicTypeMeta(ABCMeta):
|
|
|
77
77
|
else:
|
|
78
78
|
raise cls.invalid_type(value)
|
|
79
79
|
|
|
80
|
-
def is_valid(cls, value: object) -> bool:
|
|
80
|
+
def is_valid(cls: Type[Any], value: object) -> bool:
|
|
81
81
|
try:
|
|
82
82
|
cls.validate(value)
|
|
83
83
|
except (TypeError, ValueError):
|
|
@@ -85,12 +85,12 @@ class AtomicTypeMeta(ABCMeta):
|
|
|
85
85
|
else:
|
|
86
86
|
return True
|
|
87
87
|
|
|
88
|
-
def invalid_type(cls, value: object) -> TypeError:
|
|
88
|
+
def invalid_type(cls: Type[Any], value: object) -> TypeError:
|
|
89
89
|
if cls.name:
|
|
90
90
|
return TypeError('invalid type {!r} for xs:{}'.format(type(value), cls.name))
|
|
91
91
|
return TypeError('invalid type {!r} for {!r}'.format(type(value), cls))
|
|
92
92
|
|
|
93
|
-
def invalid_value(cls, value: object) -> ValueError:
|
|
93
|
+
def invalid_value(cls: Type[Any], value: object) -> ValueError:
|
|
94
94
|
if cls.name:
|
|
95
95
|
return ValueError('invalid value {!r} for xs:{}'.format(value, cls.name))
|
|
96
96
|
return ValueError('invalid value {!r} for {!r}'.format(value, cls))
|
|
@@ -12,6 +12,7 @@ import math
|
|
|
12
12
|
from calendar import isleap, leapdays
|
|
13
13
|
from decimal import Decimal
|
|
14
14
|
from operator import attrgetter
|
|
15
|
+
from urllib.parse import urlsplit
|
|
15
16
|
from typing import Any, Iterator, List, Match, Optional, Union, SupportsFloat
|
|
16
17
|
|
|
17
18
|
###
|
|
@@ -79,7 +80,7 @@ def adjust_day(year: int, month: int, day: int) -> int:
|
|
|
79
80
|
|
|
80
81
|
def days_from_common_era(year: int) -> int:
|
|
81
82
|
"""
|
|
82
|
-
Returns the number of days from
|
|
83
|
+
Returns the number of days from 0001-01-01 to the provided year. For a
|
|
83
84
|
common era year the days are counted until the last day of December, for a
|
|
84
85
|
BCE year the days are counted down from the end to the 1st of January.
|
|
85
86
|
"""
|
|
@@ -103,7 +104,7 @@ def months2days(year: int, month: int, months_delta: int) -> int:
|
|
|
103
104
|
relative to the year and the month passed as arguments.
|
|
104
105
|
|
|
105
106
|
:param year: the reference start year, a negative or zero value means a BCE year \
|
|
106
|
-
(0 is 1 BCE, -1 is 2 BCE, -2 is 3 BCE, etc).
|
|
107
|
+
(0 is 1 BCE, -1 is 2 BCE, -2 is 3 BCE, etc.).
|
|
107
108
|
:param month: the starting month (1-12).
|
|
108
109
|
:param months_delta: the number of months, if negative count backwards.
|
|
109
110
|
"""
|
|
@@ -278,3 +279,14 @@ def split_function_test(function_test: str) -> List[str]:
|
|
|
278
279
|
sequence_types = [parts[2]]
|
|
279
280
|
|
|
280
281
|
return sequence_types
|
|
282
|
+
|
|
283
|
+
|
|
284
|
+
def is_absolute_uri(uri: str) -> bool:
|
|
285
|
+
try:
|
|
286
|
+
parts = urlsplit(uri.strip())
|
|
287
|
+
except ValueError:
|
|
288
|
+
return False
|
|
289
|
+
else:
|
|
290
|
+
return parts.scheme == 'urn' or \
|
|
291
|
+
parts.scheme != '' and parts.netloc != '' or \
|
|
292
|
+
parts.path.startswith('/')
|
|
@@ -0,0 +1,178 @@
|
|
|
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
|
+
Define type hints protocols for XPath related objects.
|
|
12
|
+
"""
|
|
13
|
+
from typing import overload, Any, Dict, Iterator, Iterable, List, Literal, \
|
|
14
|
+
Optional, Protocol, Sized, Hashable, Union, TypeVar, runtime_checkable
|
|
15
|
+
|
|
16
|
+
_T = TypeVar("_T")
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@runtime_checkable
|
|
20
|
+
class ElementProtocol(Iterable['ElementProtocol'], Sized, Hashable, Protocol):
|
|
21
|
+
def find(
|
|
22
|
+
self, path: str, namespaces: Optional[Dict[str, str]] = ...
|
|
23
|
+
) -> Optional['ElementProtocol']: ...
|
|
24
|
+
def iter(self, tag: Optional[str] = ...) -> Iterator['ElementProtocol']: ...
|
|
25
|
+
@overload
|
|
26
|
+
def get(self, key: str, default: None = ...) -> Optional[str]: ...
|
|
27
|
+
# noinspection PyOverloads
|
|
28
|
+
@overload
|
|
29
|
+
def get(self, key: str, default: _T) -> Union[str, _T]: ...
|
|
30
|
+
tag: str
|
|
31
|
+
attrib: Dict[str, Any]
|
|
32
|
+
text: Optional[str]
|
|
33
|
+
tail: Optional[str]
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
@runtime_checkable
|
|
37
|
+
class LxmlElementProtocol(ElementProtocol, Protocol):
|
|
38
|
+
def getroottree(self) -> 'DocumentProtocol': ...
|
|
39
|
+
def getnext(self) -> Optional['LxmlElementProtocol']: ...
|
|
40
|
+
def getparent(self) -> Optional['LxmlElementProtocol']: ...
|
|
41
|
+
def getprevious(self) -> Optional['LxmlElementProtocol']: ...
|
|
42
|
+
def itersiblings(self, tag: Optional[str] = ..., preceding: bool = False,
|
|
43
|
+
*tags: str) -> Iterable['LxmlElementProtocol']: ...
|
|
44
|
+
nsmap: Dict[Optional[str], str]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@runtime_checkable
|
|
48
|
+
class DocumentProtocol(Iterable[ElementProtocol], Hashable, Protocol):
|
|
49
|
+
def getroot(self) -> Optional[ElementProtocol]: ...
|
|
50
|
+
def parse(self, source: Any, *args: Any, **kwargs: Any) -> 'DocumentProtocol': ...
|
|
51
|
+
def iter(self, tag: Optional[str] = ...) -> Iterator[ElementProtocol]: ...
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@runtime_checkable
|
|
55
|
+
class XsdValidatorProtocol(Protocol):
|
|
56
|
+
def is_matching(self, name: Optional[str],
|
|
57
|
+
default_namespace: Optional[str] = None) -> bool: ...
|
|
58
|
+
xsd_version: Literal['1.0', '1.1']
|
|
59
|
+
name: Optional[str]
|
|
60
|
+
maps: 'GlobalMapsProtocol'
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
@runtime_checkable
|
|
64
|
+
class XsdSchemaProtocol(XsdValidatorProtocol, ElementProtocol, Protocol):
|
|
65
|
+
tag: Literal['{http://www.w3.org/2001/XMLSchema}schema']
|
|
66
|
+
attrib: Dict[str, 'XsdAttributeProtocol']
|
|
67
|
+
text: None
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
XMLSchemaProtocol = XsdSchemaProtocol # for backward compatibility
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
@runtime_checkable
|
|
74
|
+
class XsdComponentProtocol(XsdValidatorProtocol, Protocol):
|
|
75
|
+
parent: Optional['XsdComponentProtocol']
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
@runtime_checkable
|
|
79
|
+
class XsdTypeProtocol(XsdComponentProtocol, Protocol):
|
|
80
|
+
def is_simple(self) -> bool:
|
|
81
|
+
"""Returns `True` if it's a simpleType instance, `False` if it's a complexType."""
|
|
82
|
+
...
|
|
83
|
+
|
|
84
|
+
def is_empty(self) -> bool:
|
|
85
|
+
"""
|
|
86
|
+
Returns `True` if it's a simpleType instance or a complexType with empty content,
|
|
87
|
+
`False` otherwise.
|
|
88
|
+
"""
|
|
89
|
+
...
|
|
90
|
+
|
|
91
|
+
def has_simple_content(self) -> bool:
|
|
92
|
+
"""
|
|
93
|
+
Returns `True` if it's a simpleType instance or a complexType with simple content,
|
|
94
|
+
`False` otherwise.
|
|
95
|
+
"""
|
|
96
|
+
...
|
|
97
|
+
|
|
98
|
+
def has_mixed_content(self) -> bool:
|
|
99
|
+
"""
|
|
100
|
+
Returns `True` if it's a complexType with mixed content, `False` otherwise.
|
|
101
|
+
"""
|
|
102
|
+
...
|
|
103
|
+
|
|
104
|
+
def is_element_only(self) -> bool:
|
|
105
|
+
"""
|
|
106
|
+
Returns `True` if it's a complexType with element-only content, `False` otherwise.
|
|
107
|
+
"""
|
|
108
|
+
...
|
|
109
|
+
|
|
110
|
+
def is_key(self) -> bool:
|
|
111
|
+
"""Returns `True` if it's a simpleType derived from xs:ID, `False` otherwise."""
|
|
112
|
+
...
|
|
113
|
+
|
|
114
|
+
def is_qname(self) -> bool:
|
|
115
|
+
"""Returns `True` if it's a simpleType derived from xs:QName, `False` otherwise."""
|
|
116
|
+
...
|
|
117
|
+
|
|
118
|
+
def is_notation(self) -> bool:
|
|
119
|
+
"""Returns `True` if it's a simpleType derived from xs:NOTATION, `False` otherwise."""
|
|
120
|
+
...
|
|
121
|
+
|
|
122
|
+
def is_valid(self, obj: Any, *args: Any, **kwargs: Any) -> bool:
|
|
123
|
+
"""
|
|
124
|
+
Validates an XML object node using the XSD type. The argument *obj* is an element
|
|
125
|
+
for complex type nodes or a text value for simple type nodes. Returns `True` if
|
|
126
|
+
the argument is valid, `False` otherwise.
|
|
127
|
+
"""
|
|
128
|
+
...
|
|
129
|
+
|
|
130
|
+
def validate(self, obj: Any, *args: Any, **kwargs: Any) -> None:
|
|
131
|
+
"""
|
|
132
|
+
Validates an XML object node using the XSD type. The argument *obj* is an element
|
|
133
|
+
for complex type nodes or a text value for simple type nodes. Raises a `ValueError`
|
|
134
|
+
compatible exception (a `ValueError` or a subclass of it) if the argument is not valid.
|
|
135
|
+
"""
|
|
136
|
+
...
|
|
137
|
+
|
|
138
|
+
def decode(self, obj: Any, *args: Any, **kwargs: Any) -> Any:
|
|
139
|
+
"""
|
|
140
|
+
Decodes an XML object node using the XSD type. The argument *obj* is an element
|
|
141
|
+
for complex type nodes or a text value for simple type nodes. Raises a `ValueError`
|
|
142
|
+
or a `TypeError` compatible exception if the argument it's not valid.
|
|
143
|
+
"""
|
|
144
|
+
...
|
|
145
|
+
|
|
146
|
+
root_type: 'XsdTypeProtocol'
|
|
147
|
+
"""
|
|
148
|
+
The type at base of the definition of the XSD type. For a special type is the type
|
|
149
|
+
itself. For an atomic type is the primitive type. For a list is the primitive type
|
|
150
|
+
of the item. For a union is the base union type. For a complex type is xs:anyType.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
|
|
154
|
+
@runtime_checkable
|
|
155
|
+
class XsdAttributeProtocol(XsdComponentProtocol, Protocol):
|
|
156
|
+
type: Optional[XsdTypeProtocol]
|
|
157
|
+
ref: Optional['XsdAttributeProtocol']
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
@runtime_checkable
|
|
161
|
+
class XsdElementProtocol(XsdComponentProtocol, ElementProtocol, Protocol):
|
|
162
|
+
type: Optional[XsdTypeProtocol]
|
|
163
|
+
ref: Optional['XsdElementProtocol']
|
|
164
|
+
attrib: Dict[str, XsdAttributeProtocol]
|
|
165
|
+
text: None
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class GlobalMapsProtocol(Protocol):
|
|
169
|
+
types: Dict[str, XsdTypeProtocol]
|
|
170
|
+
attributes: Dict[str, XsdAttributeProtocol]
|
|
171
|
+
elements: Dict[str, XsdElementProtocol]
|
|
172
|
+
substitution_groups: Dict[str, List[XsdElementProtocol]]
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
__all__ = ['ElementProtocol', 'LxmlElementProtocol', 'DocumentProtocol',
|
|
176
|
+
'XsdValidatorProtocol', 'XsdSchemaProtocol', 'XsdComponentProtocol',
|
|
177
|
+
'XsdTypeProtocol', 'XsdElementProtocol', 'XsdAttributeProtocol',
|
|
178
|
+
'GlobalMapsProtocol', 'XMLSchemaProtocol']
|
|
@@ -398,7 +398,7 @@ class ParserMeta(ABCMeta):
|
|
|
398
398
|
literals_pattern: Pattern[str]
|
|
399
399
|
name_pattern: Pattern[str]
|
|
400
400
|
tokenizer: Optional[Pattern[str]]
|
|
401
|
-
symbol_table:
|
|
401
|
+
symbol_table: MutableMapping[str, Type[Any]]
|
|
402
402
|
|
|
403
403
|
def __new__(mcs, name: str, bases: Tuple[Type[Any], ...], namespace: Dict[str, Any]) \
|
|
404
404
|
-> 'ParserMeta':
|
|
@@ -437,14 +437,12 @@ class Parser(Generic[TK_co], metaclass=ParserMeta):
|
|
|
437
437
|
Parser class for implementing a Top-Down Operator Precedence parser.
|
|
438
438
|
|
|
439
439
|
:cvar symbol_table: a dictionary that stores the token classes defined for the language.
|
|
440
|
-
:type symbol_table: dict
|
|
441
440
|
:cvar token_base_class: the base class for creating language's token classes.
|
|
442
|
-
:type token_base_class: Token
|
|
443
441
|
:cvar tokenizer: the language tokenizer compiled regexp.
|
|
444
442
|
"""
|
|
445
443
|
token_base_class = Token
|
|
446
444
|
tokenizer: Optional[Pattern[str]] = None
|
|
447
|
-
symbol_table:
|
|
445
|
+
symbol_table: Dict[str, Type[TK_co]] = {}
|
|
448
446
|
|
|
449
447
|
_start_token: TK_co
|
|
450
448
|
source: str
|
|
@@ -667,6 +665,8 @@ class Parser(Generic[TK_co], metaclass=ParserMeta):
|
|
|
667
665
|
:param kwargs: Optional attributes/methods for the token class.
|
|
668
666
|
:return: A token class.
|
|
669
667
|
"""
|
|
668
|
+
token_class: Type[TK_co]
|
|
669
|
+
|
|
670
670
|
if isinstance(symbol, str):
|
|
671
671
|
if ' ' in symbol:
|
|
672
672
|
raise ValueError("%r: a symbol can't contain whitespaces" % symbol)
|