maxml 1.0.3__tar.gz → 1.0.5__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxml
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: A streamlined pure Python XML serializer.
5
5
  Author: Daniel Sissman
6
6
  License-Expression: MIT
@@ -19,9 +19,9 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  Requires-Dist: classicist==1.0.*
22
- Requires-Dist: enumerific==1.0.*
22
+ Requires-Dist: enumerific==1.1.*
23
23
  Provides-Extra: development
24
- Requires-Dist: black==24.10.*; extra == "development"
24
+ Requires-Dist: black==26.1.*; extra == "development"
25
25
  Requires-Dist: pytest==8.3.*; extra == "development"
26
26
  Requires-Dist: pytest-codeblocks==0.17.0; extra == "development"
27
27
  Provides-Extra: distribution
@@ -115,10 +115,10 @@ The `Element` class constructor `Element(...)` takes the following arguments:
115
115
 
116
116
  The `Element` class provides the following methods:
117
117
 
118
- * `register_namespace(prefix: str, uri: str)` The `register_namespace()` method
119
- supports registering namespaces globally for the module or per instance depending
120
- on whether the method is called on the class directly or whether it is called on a
121
- specific instance of the class.
118
+ * `register_namespace(prefix: str, uri: str, promoted: bool = False)`
119
+ The `register_namespace()` method supports registering namespaces globally for the
120
+ module or per instance depending on whether the method is called on the class
121
+ directly or whether it is called on a specific instance of the class.
122
122
 
123
123
  If a namespace is registered globally for the module, the registered namespaces
124
124
  become available for use by any instance of the class created within the program
@@ -132,6 +132,16 @@ The `Element` class provides the following methods:
132
132
 
133
133
  Each namespace consists of a prefix which can be used to prefix element names
134
134
  and the URI associated with that namespace prefix.
135
+
136
+ Optionally, a namespace can be marked as being promoted during registration, which
137
+ will result in the namespace being serialized into the XML before any attributes on
138
+ the element. Namespaces that are not marked as being promoted will appear after any
139
+ attributes on the element. Namespace promotion can be enabled for a given namespace
140
+ during registration by passing the optional `promoted` keyword argument with the
141
+ value of `True`. Whether a namespace is marked as promoted or not can be changed
142
+ after registration by changing a `Namespace` entity's `promoted` property value or
143
+ by using the `promote()` and `unpromote()` methods. See the **Namespace Class** for
144
+ more information.
135
145
 
136
146
  For example, the 'rdf' prefix is associated with the following canonical URI:
137
147
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
@@ -278,6 +288,9 @@ The `Namespace` class constructor `Namespace(...)` takes the following arguments
278
288
 
279
289
  * `prefix` (`str`) – The required `prefix` argument sets the namespace prefix.
280
290
  * `uri` (`str`) – The required `uri` argument sets the namespace URI.
291
+ * `promoted` (`bool`) – The optional `promoted` argument sets whether the namespace is
292
+ marked as being promoted or not. Promoted namespaces result in the namespace being
293
+ serialized into the XML before any attributes on their associated element.
281
294
 
282
295
  The `Namespace` class provides the following methods:
283
296
 
@@ -84,10 +84,10 @@ The `Element` class constructor `Element(...)` takes the following arguments:
84
84
 
85
85
  The `Element` class provides the following methods:
86
86
 
87
- * `register_namespace(prefix: str, uri: str)` The `register_namespace()` method
88
- supports registering namespaces globally for the module or per instance depending
89
- on whether the method is called on the class directly or whether it is called on a
90
- specific instance of the class.
87
+ * `register_namespace(prefix: str, uri: str, promoted: bool = False)`
88
+ The `register_namespace()` method supports registering namespaces globally for the
89
+ module or per instance depending on whether the method is called on the class
90
+ directly or whether it is called on a specific instance of the class.
91
91
 
92
92
  If a namespace is registered globally for the module, the registered namespaces
93
93
  become available for use by any instance of the class created within the program
@@ -101,6 +101,16 @@ The `Element` class provides the following methods:
101
101
 
102
102
  Each namespace consists of a prefix which can be used to prefix element names
103
103
  and the URI associated with that namespace prefix.
104
+
105
+ Optionally, a namespace can be marked as being promoted during registration, which
106
+ will result in the namespace being serialized into the XML before any attributes on
107
+ the element. Namespaces that are not marked as being promoted will appear after any
108
+ attributes on the element. Namespace promotion can be enabled for a given namespace
109
+ during registration by passing the optional `promoted` keyword argument with the
110
+ value of `True`. Whether a namespace is marked as promoted or not can be changed
111
+ after registration by changing a `Namespace` entity's `promoted` property value or
112
+ by using the `promote()` and `unpromote()` methods. See the **Namespace Class** for
113
+ more information.
104
114
 
105
115
  For example, the 'rdf' prefix is associated with the following canonical URI:
106
116
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
@@ -247,6 +257,9 @@ The `Namespace` class constructor `Namespace(...)` takes the following arguments
247
257
 
248
258
  * `prefix` (`str`) – The required `prefix` argument sets the namespace prefix.
249
259
  * `uri` (`str`) – The required `uri` argument sets the namespace URI.
260
+ * `promoted` (`bool`) – The optional `promoted` argument sets whether the namespace is
261
+ marked as being promoted or not. Promoted namespaces result in the namespace being
262
+ serialized into the XML before any attributes on their associated element.
250
263
 
251
264
  The `Namespace` class provides the following methods:
252
265
 
@@ -1,4 +1,4 @@
1
1
  # MaXML Library: Development & Test Dependencies
2
- black==24.10.*
2
+ black==26.1.*
3
3
  pytest==8.3.*
4
4
  pytest-codeblocks==0.17.0
@@ -1,3 +1,3 @@
1
1
  # MaXML Library: Runtime Dependencies
2
2
  classicist==1.0.*
3
- enumerific==1.0.*
3
+ enumerific==1.1.*
@@ -28,7 +28,7 @@ class Element(object):
28
28
  _mixed: bool = False
29
29
 
30
30
  @hybridmethod
31
- def register_namespace(self, prefix: str, uri: str):
31
+ def register_namespace(self, prefix: str, uri: str, promoted: bool = False):
32
32
  """Supports registering namespaces globally for the module or per instance
33
33
  depending on whether the method is called on the class directly or whether it is
34
34
  called on a specific instance of the class.
@@ -74,6 +74,9 @@ class Element(object):
74
74
  if not isinstance(uri, str):
75
75
  raise TypeError("The 'uri' argument must have a string value!")
76
76
 
77
+ if not isinstance(promoted, bool):
78
+ raise TypeError("The 'promoted' argument must have a boolean value!")
79
+
77
80
  for namespace in self._namespaces:
78
81
  if namespace.prefix == prefix:
79
82
  if namespace.uri == uri:
@@ -88,7 +91,7 @@ class Element(object):
88
91
  % (prefix, uri, namespace.uri)
89
92
  )
90
93
  else:
91
- if namespace := Namespace(prefix=prefix, uri=uri):
94
+ if namespace := Namespace(prefix=prefix, uri=uri, promoted=promoted):
92
95
  self._namespaces.add(namespace)
93
96
 
94
97
  def __init__(
@@ -119,7 +122,7 @@ class Element(object):
119
122
  prefix: str = None
120
123
 
121
124
  if ":" in name:
122
- (prefix, basename) = name.split(":", maxsplit=1)
125
+ prefix, basename = name.split(":", maxsplit=1)
123
126
 
124
127
  self._prefix: str = prefix
125
128
 
@@ -186,7 +189,7 @@ class Element(object):
186
189
  if namespace.uri == uri:
187
190
  break
188
191
  else:
189
- namespace = Namespace(prefix=prefix, uri=uri)
192
+ namespace = Namespace(prefix=prefix, uri=uri, promoted=False)
190
193
 
191
194
  self.__class__._namespaces.add(namespace)
192
195
 
@@ -662,7 +665,7 @@ class Element(object):
662
665
  # Add any promoted namespaces (those which should proceed any attributes)
663
666
  count = len(element.namespaced)
664
667
  for index, namespace in enumerate(element.namespaced, start=1):
665
- if not namespace.promoted:
668
+ if namespace.promoted is False:
666
669
  continue
667
670
 
668
671
  if pretty and count > 1 and (newline or (index > 1 and index <= count)):
@@ -691,7 +694,7 @@ class Element(object):
691
694
  newline = True
692
695
 
693
696
  for index, namespace in enumerate(element.namespaced, start=1):
694
- if namespace.promoted:
697
+ if namespace.promoted is True:
695
698
  continue
696
699
 
697
700
  if pretty and count > 1 and (newline or (index > 1 and index <= count)):
@@ -14,7 +14,7 @@ class Namespace(object):
14
14
  _uri: str = None
15
15
  _promoted: bool = False
16
16
 
17
- def __init__(self, prefix: str, uri: str):
17
+ def __init__(self, prefix: str, uri: str, promoted: bool = False):
18
18
  """Initialize the Namespace class"""
19
19
 
20
20
  if not isinstance(prefix, str):
@@ -27,6 +27,11 @@ class Namespace(object):
27
27
 
28
28
  self._uri = uri
29
29
 
30
+ if not isinstance(promoted, bool):
31
+ raise TypeError("The 'promoted' argument must have a boolean value!")
32
+
33
+ self._promoted = promoted
34
+
30
35
  def __str__(self) -> str:
31
36
  """Return a string representation of the class for debugging purposes."""
32
37
 
@@ -89,7 +94,7 @@ class Namespace(object):
89
94
  def copy(self) -> Namespace:
90
95
  """Create an independent copy of the current Namespace instance."""
91
96
 
92
- return Namespace(prefix=self.prefix, uri=self.uri)
97
+ return Namespace(prefix=self.prefix, uri=self.uri, promoted=self.promoted)
93
98
 
94
99
  @property
95
100
  def promoted(self) -> bool:
@@ -0,0 +1 @@
1
+ 1.0.5
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: maxml
3
- Version: 1.0.3
3
+ Version: 1.0.5
4
4
  Summary: A streamlined pure Python XML serializer.
5
5
  Author: Daniel Sissman
6
6
  License-Expression: MIT
@@ -19,9 +19,9 @@ Classifier: Programming Language :: Python :: 3.13
19
19
  Requires-Python: >=3.10
20
20
  Description-Content-Type: text/markdown
21
21
  Requires-Dist: classicist==1.0.*
22
- Requires-Dist: enumerific==1.0.*
22
+ Requires-Dist: enumerific==1.1.*
23
23
  Provides-Extra: development
24
- Requires-Dist: black==24.10.*; extra == "development"
24
+ Requires-Dist: black==26.1.*; extra == "development"
25
25
  Requires-Dist: pytest==8.3.*; extra == "development"
26
26
  Requires-Dist: pytest-codeblocks==0.17.0; extra == "development"
27
27
  Provides-Extra: distribution
@@ -115,10 +115,10 @@ The `Element` class constructor `Element(...)` takes the following arguments:
115
115
 
116
116
  The `Element` class provides the following methods:
117
117
 
118
- * `register_namespace(prefix: str, uri: str)` The `register_namespace()` method
119
- supports registering namespaces globally for the module or per instance depending
120
- on whether the method is called on the class directly or whether it is called on a
121
- specific instance of the class.
118
+ * `register_namespace(prefix: str, uri: str, promoted: bool = False)`
119
+ The `register_namespace()` method supports registering namespaces globally for the
120
+ module or per instance depending on whether the method is called on the class
121
+ directly or whether it is called on a specific instance of the class.
122
122
 
123
123
  If a namespace is registered globally for the module, the registered namespaces
124
124
  become available for use by any instance of the class created within the program
@@ -132,6 +132,16 @@ The `Element` class provides the following methods:
132
132
 
133
133
  Each namespace consists of a prefix which can be used to prefix element names
134
134
  and the URI associated with that namespace prefix.
135
+
136
+ Optionally, a namespace can be marked as being promoted during registration, which
137
+ will result in the namespace being serialized into the XML before any attributes on
138
+ the element. Namespaces that are not marked as being promoted will appear after any
139
+ attributes on the element. Namespace promotion can be enabled for a given namespace
140
+ during registration by passing the optional `promoted` keyword argument with the
141
+ value of `True`. Whether a namespace is marked as promoted or not can be changed
142
+ after registration by changing a `Namespace` entity's `promoted` property value or
143
+ by using the `promote()` and `unpromote()` methods. See the **Namespace Class** for
144
+ more information.
135
145
 
136
146
  For example, the 'rdf' prefix is associated with the following canonical URI:
137
147
  "http://www.w3.org/1999/02/22-rdf-syntax-ns#"
@@ -278,6 +288,9 @@ The `Namespace` class constructor `Namespace(...)` takes the following arguments
278
288
 
279
289
  * `prefix` (`str`) – The required `prefix` argument sets the namespace prefix.
280
290
  * `uri` (`str`) – The required `uri` argument sets the namespace URI.
291
+ * `promoted` (`bool`) – The optional `promoted` argument sets whether the namespace is
292
+ marked as being promoted or not. Promoted namespaces result in the namespace being
293
+ serialized into the XML before any attributes on their associated element.
281
294
 
282
295
  The `Namespace` class provides the following methods:
283
296
 
@@ -1,8 +1,8 @@
1
1
  classicist==1.0.*
2
- enumerific==1.0.*
2
+ enumerific==1.1.*
3
3
 
4
4
  [development]
5
- black==24.10.*
5
+ black==26.1.*
6
6
  pytest==8.3.*
7
7
  pytest-codeblocks==0.17.0
8
8
 
@@ -461,3 +461,99 @@ def test_maxml_special_tostring(data: callable):
461
461
  assert isinstance(compare, str)
462
462
 
463
463
  assert string == compare
464
+
465
+
466
+ def test_maxml_namespace_promotion(data: callable):
467
+ """Check promotion of registered namespaces works as expected"""
468
+
469
+ # Register a class level namespace
470
+ maxml.Element.register_namespace(
471
+ prefix="xy", uri="http://namespace.example.org/xy", promoted=True
472
+ )
473
+
474
+ # Create a new top-level element
475
+ element = maxml.Element(name="xy:test")
476
+
477
+ # Ensure that the Element object's type is as expected
478
+ assert isinstance(element, maxml.Element)
479
+
480
+ # Ensure that the Element object's namespace type is as expected
481
+ assert isinstance(element.namespace, maxml.Namespace)
482
+ assert element.namespace.prefix == "xy"
483
+ assert element.namespace.uri == "http://namespace.example.org/xy"
484
+ assert element.namespace.promoted is True
485
+
486
+ # Set an element attribute
487
+ element.set("xy:id", "1")
488
+
489
+ # Serialise the element to a string
490
+ string: str = element.tostring(pretty=True)
491
+
492
+ assert isinstance(string, str)
493
+
494
+ # Confirm that the promoted namespace was serialised before the attributes
495
+ compare: str = """<xy:test xmlns:xy="http://namespace.example.org/xy" xy:id="1"/>"""
496
+
497
+ assert string == compare
498
+
499
+ # Now mark the namespace as not being promoted to re-test the serialisation below
500
+ element.namespace.promoted = False
501
+
502
+ # Ensure that the promoted status has changed
503
+ assert element.namespace.promoted is False
504
+
505
+ # Serialise the element to a string
506
+ string: str = element.tostring(pretty=True)
507
+
508
+ assert isinstance(string, str)
509
+
510
+ # Confirm that the non-promoted namespace was serialised after the attributes
511
+ compare: str = """<xy:test xy:id="1" xmlns:xy="http://namespace.example.org/xy"/>"""
512
+
513
+ assert string == compare
514
+
515
+
516
+ def test_maxml_namespace_promotion_non_promoted_namespace(data: callable):
517
+ """Check promotion of registered namespaces works as expected"""
518
+
519
+ maxml.Element.register_namespace(
520
+ prefix="my1", uri="http://namespace.example.org/my1", promoted=False
521
+ )
522
+
523
+ element = maxml.Element(name="my1:test")
524
+
525
+ # Ensure that the element object's type is as expected
526
+ assert isinstance(element, maxml.Element)
527
+
528
+ element.set("my1:attribute", "1234")
529
+
530
+ string: str = element.tostring(pretty=True)
531
+
532
+ assert isinstance(string, str)
533
+
534
+ compare: str = data("examples/example04namespace-unpromoted.xml")
535
+
536
+ assert string == compare
537
+
538
+
539
+ def test_maxml_namespace_promotion_promoted_namespace(data: callable):
540
+ """Check promotion of registered namespaces works as expected"""
541
+
542
+ maxml.Element.register_namespace(
543
+ prefix="my2", uri="http://namespace.example.org/my2", promoted=True
544
+ )
545
+
546
+ element = maxml.Element(name="my2:test")
547
+
548
+ # Ensure that the element object's type is as expected
549
+ assert isinstance(element, maxml.Element)
550
+
551
+ element.set("my2:attribute", "1234")
552
+
553
+ string: str = element.tostring(pretty=True)
554
+
555
+ assert isinstance(string, str)
556
+
557
+ compare: str = data("examples/example04namespace-promoted.xml")
558
+
559
+ assert string == compare
@@ -1 +0,0 @@
1
- 1.0.3
File without changes
File without changes
File without changes
File without changes