elementpath 4.1.4__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.
Files changed (126) hide show
  1. {elementpath-4.1.4 → elementpath-4.2.0}/CHANGELOG.rst +13 -0
  2. {elementpath-4.1.4 → elementpath-4.2.0}/PKG-INFO +13 -4
  3. {elementpath-4.1.4 → elementpath-4.2.0}/doc/advanced.rst +41 -5
  4. {elementpath-4.1.4 → elementpath-4.2.0}/doc/conf.py +3 -3
  5. elementpath-4.2.0/doc/requirements.txt +2 -0
  6. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/__init__.py +2 -2
  7. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/compare.py +4 -4
  8. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/atomic_types.py +4 -4
  9. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/helpers.py +14 -2
  10. elementpath-4.2.0/elementpath/protocols.py +178 -0
  11. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/tdop.py +4 -4
  12. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/tree_builders.py +75 -28
  13. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_functions.py +4 -11
  14. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_operators.py +6 -6
  15. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath1/xpath1_parser.py +37 -1
  16. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_functions.py +2 -4
  17. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_operators.py +4 -8
  18. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/_xpath30_functions.py +4 -28
  19. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath_context.py +209 -198
  20. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath_nodes.py +100 -63
  21. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath_tokens.py +69 -61
  22. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath.egg-info/PKG-INFO +13 -4
  23. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath.egg-info/SOURCES.txt +1 -0
  24. {elementpath-4.1.4 → elementpath-4.2.0}/setup.py +2 -3
  25. {elementpath-4.1.4 → elementpath-4.2.0}/tests/execute_w3c_tests.py +1 -1
  26. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_package.py +37 -2
  27. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_tree_builders.py +36 -1
  28. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_validators.py +7 -0
  29. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath1_parser.py +35 -4
  30. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath2_functions.py +12 -3
  31. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath2_parser.py +1 -1
  32. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath30.py +2 -1
  33. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath_context.py +106 -2
  34. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath_nodes.py +40 -5
  35. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath_tokens.py +1 -1
  36. {elementpath-4.1.4 → elementpath-4.2.0}/tox.ini +27 -13
  37. elementpath-4.1.4/elementpath/protocols.py +0 -184
  38. {elementpath-4.1.4 → elementpath-4.2.0}/.coveragerc +0 -0
  39. {elementpath-4.1.4 → elementpath-4.2.0}/LICENSE +0 -0
  40. {elementpath-4.1.4 → elementpath-4.2.0}/MANIFEST.in +0 -0
  41. {elementpath-4.1.4 → elementpath-4.2.0}/README.rst +0 -0
  42. {elementpath-4.1.4 → elementpath-4.2.0}/doc/Makefile +0 -0
  43. {elementpath-4.1.4 → elementpath-4.2.0}/doc/index.rst +0 -0
  44. {elementpath-4.1.4 → elementpath-4.2.0}/doc/introduction.rst +0 -0
  45. {elementpath-4.1.4 → elementpath-4.2.0}/doc/make.bat +0 -0
  46. {elementpath-4.1.4 → elementpath-4.2.0}/doc/pratt_api.rst +0 -0
  47. {elementpath-4.1.4 → elementpath-4.2.0}/doc/xpath_api.rst +0 -0
  48. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/collations.py +0 -0
  49. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/__init__.py +0 -0
  50. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/binary.py +0 -0
  51. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/datetime.py +0 -0
  52. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/numeric.py +0 -0
  53. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/proxies.py +0 -0
  54. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/qname.py +0 -0
  55. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/string.py +0 -0
  56. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/untyped.py +0 -0
  57. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/datatypes/uri.py +0 -0
  58. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/etree.py +0 -0
  59. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/exceptions.py +0 -0
  60. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/namespaces.py +0 -0
  61. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/py.typed +0 -0
  62. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/__init__.py +0 -0
  63. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/character_classes.py +0 -0
  64. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/codepoints.py +0 -0
  65. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/generate_categories.py +0 -0
  66. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/patterns.py +0 -0
  67. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/unicode_categories.py +0 -0
  68. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/regex/unicode_subsets.py +0 -0
  69. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/schema_proxy.py +0 -0
  70. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/sequence_types.py +0 -0
  71. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/serialization.py +0 -0
  72. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/validators/__init__.py +0 -0
  73. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/validators/analyze-string.xsd +0 -0
  74. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/validators/schema-for-json.xsd +0 -0
  75. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath1/__init__.py +0 -0
  76. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath1/_xpath1_axes.py +0 -0
  77. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath2/__init__.py +0 -0
  78. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath2/_xpath2_constructors.py +0 -0
  79. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath2/xpath2_parser.py +0 -0
  80. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath3.py +0 -0
  81. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/__init__.py +0 -0
  82. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/_translation_maps.py +0 -0
  83. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/_xpath30_operators.py +0 -0
  84. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/xpath30_helpers.py +0 -0
  85. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath30/xpath30_parser.py +0 -0
  86. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath31/__init__.py +0 -0
  87. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath31/_xpath31_functions.py +0 -0
  88. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath31/_xpath31_operators.py +0 -0
  89. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath31/xpath31_parser.py +0 -0
  90. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath/xpath_selectors.py +0 -0
  91. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath.egg-info/dependency_links.txt +0 -0
  92. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath.egg-info/requires.txt +0 -0
  93. {elementpath-4.1.4 → elementpath-4.2.0}/elementpath.egg-info/top_level.txt +0 -0
  94. {elementpath-4.1.4 → elementpath-4.2.0}/mypy.ini +0 -0
  95. {elementpath-4.1.4 → elementpath-4.2.0}/requirements-dev.txt +0 -0
  96. {elementpath-4.1.4 → elementpath-4.2.0}/setup.cfg +0 -0
  97. {elementpath-4.1.4 → elementpath-4.2.0}/tests/__init__.py +0 -0
  98. {elementpath-4.1.4 → elementpath-4.2.0}/tests/memory_profiling.py +0 -0
  99. {elementpath-4.1.4 → elementpath-4.2.0}/tests/mypy_tests/selectors.py +0 -0
  100. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/analyze-string.xsd +0 -0
  101. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/external_entity.xml +0 -0
  102. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/sample.xml +0 -0
  103. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/schema-for-json.xsd +0 -0
  104. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/unparsed_entity.xml +0 -0
  105. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/unused_external_entity.xml +0 -0
  106. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/unused_unparsed_entity.xml +0 -0
  107. {elementpath-4.1.4 → elementpath-4.2.0}/tests/resources/with_entity.xml +0 -0
  108. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_collations.py +0 -0
  109. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_compare.py +0 -0
  110. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_datatypes.py +0 -0
  111. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_elementpath.py +0 -0
  112. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_etree.py +0 -0
  113. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_exceptions.py +0 -0
  114. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_helpers.py +0 -0
  115. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_namespaces.py +0 -0
  116. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_regex.py +0 -0
  117. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_schema_context.py +0 -0
  118. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_schema_proxy.py +0 -0
  119. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_selectors.py +0 -0
  120. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_sequence_types.py +0 -0
  121. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_serialization.py +0 -0
  122. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_tdop_parser.py +0 -0
  123. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_typing.py +0 -0
  124. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath2_constructors.py +0 -0
  125. {elementpath-4.1.4 → elementpath-4.2.0}/tests/test_xpath31.py +0 -0
  126. {elementpath-4.1.4 → elementpath-4.2.0}/tests/xpath_test_class.py +0 -0
@@ -2,6 +2,17 @@
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
+
12
+ `v4.1.5`_ (2023-07-25)
13
+ ======================
14
+ * Fix typed value of ElementNode() if self.elem.text is None
15
+
5
16
  `v4.1.4`_ (2023-06-26)
6
17
  ======================
7
18
  * Fix select of prefixed names (issue #68)
@@ -430,3 +441,5 @@ CHANGELOG
430
441
  .. _v4.1.2: https://github.com/sissaschool/elementpath/compare/v4.1.1...v4.1.2
431
442
  .. _v4.1.3: https://github.com/sissaschool/elementpath/compare/v4.1.2...v4.1.3
432
443
  .. _v4.1.4: https://github.com/sissaschool/elementpath/compare/v4.1.3...v4.1.4
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.1.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.7
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 not set:
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 None
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
- ElementNode(elem=<Element root at ...>)
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-2023, SISSA (International School for Advanced Studies)'
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.1'
32
+ version = '4.2'
33
33
  # The full version, including alpha/beta/rc tags
34
- release = '4.1.4'
34
+ release = '4.2.0'
35
35
 
36
36
  # -- General configuration ---------------------------------------------------
37
37
 
@@ -0,0 +1,2 @@
1
+ Sphinx==7.2.6
2
+ readthedocs-sphinx-search==0.3.2
@@ -7,10 +7,10 @@
7
7
  #
8
8
  # @author Davide Brunato <brunato@sissa.it>
9
9
  #
10
- __version__ = '4.1.4'
10
+ __version__ = '4.2.0'
11
11
  __author__ = "Davide Brunato"
12
12
  __contact__ = "brunato@sissa.it"
13
- __copyright__ = "Copyright 2018-2023, SISSA"
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): # type: ignore[arg-type]
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 # type: ignore[operator]
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 # type: ignore[operator]
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 # type: ignore[operator]
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 from 0001-01-01 to the provided year. For a
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: Dict[str, Token[Any]]
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: MutableMapping[str, Type[TK_co]] = {}
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)