pyRegRep 12__tar.gz → 13__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: pyRegRep
3
- Version: 12
3
+ Version: 13
4
4
  Summary: Your package description
5
5
  Author: Andrey Shapovalov
6
6
  Author-email: mt.andrey@gmail.com
@@ -28,6 +28,7 @@ Dynamic: license-file
28
28
  - ✅ Обробка всіх типів значень: Boolean, String, Integer, DateTime, Collection, InternationalString, AnyValue
29
29
  - ✅ Серіалізація даних у зручний Python-формат (`dict`)
30
30
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
31
+ - ✅ Builder-класи для елементів `RegistryObject`, `RepositoryItemRef`, `QueryResponse`, `Classification`
31
32
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
32
33
  - ✅ Підтримка вкладених колекцій та складних структур
33
34
  - ✅ Безпечний доступ до вкладених даних через `deep_get()`
@@ -198,6 +199,38 @@ except ValueError as e:
198
199
 
199
200
  ---
200
201
 
202
+ ### Builder-класи XML елементів (`pyRegRep4.RIMElement`)
203
+
204
+ Публічні класи для побудови типових елементів RIM/query:
205
+
206
+ - `RegistryObject`
207
+ - `RepositoryItemRef`
208
+ - `QueryResponse`
209
+ - `Classification`
210
+
211
+ Усі класи мають однаковий базовий контракт:
212
+ - `element` — повертає `etree._Element` (або `ValueError`, якщо елемент ще не створено)
213
+ - `text` — серіалізований XML (`bytes`)
214
+ - `create_element(...)` — будує XML елемент і повертає `self` (chain-style)
215
+
216
+ ```python
217
+ from pyRegRep4.RIMElement import RepositoryItemRef, QueryResponse
218
+
219
+ ref = RepositoryItemRef().create_element(
220
+ "https://example.org/document.xml",
221
+ "Document",
222
+ )
223
+ print(ref.text)
224
+
225
+ response = QueryResponse().create_element(
226
+ "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success",
227
+ "req-1",
228
+ )
229
+ print(response.element.tag)
230
+ ```
231
+
232
+ ---
233
+
201
234
  ### Функція `deep_get()` (`pyRegRep4.utils`)
202
235
 
203
236
  ```python
@@ -250,7 +283,7 @@ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
250
283
  ```
251
284
  pyRegRep/
252
285
  ├── pyRegRep4/
253
- │ ├── __init__.py # Експорт: get_slot та типи слотів
286
+ │ ├── __init__.py # Експорт: get_slot, deep_get, Parsing, serialize_any_value_type
254
287
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
255
288
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
256
289
  │ ├── utils.py # deep_get() для вкладених словників
@@ -337,4 +370,4 @@ MIT License — див. файл [LICENSE](LICENSE)
337
370
 
338
371
  ---
339
372
 
340
- **Версія:** 12 · **Оновлено:** 2026-04-12
373
+ **Версія:** 13 · **Оновлено:** 2026-04-14
@@ -14,6 +14,7 @@
14
14
  - ✅ Обробка всіх типів значень: Boolean, String, Integer, DateTime, Collection, InternationalString, AnyValue
15
15
  - ✅ Серіалізація даних у зручний Python-формат (`dict`)
16
16
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
17
+ - ✅ Builder-класи для елементів `RegistryObject`, `RepositoryItemRef`, `QueryResponse`, `Classification`
17
18
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
18
19
  - ✅ Підтримка вкладених колекцій та складних структур
19
20
  - ✅ Безпечний доступ до вкладених даних через `deep_get()`
@@ -184,6 +185,38 @@ except ValueError as e:
184
185
 
185
186
  ---
186
187
 
188
+ ### Builder-класи XML елементів (`pyRegRep4.RIMElement`)
189
+
190
+ Публічні класи для побудови типових елементів RIM/query:
191
+
192
+ - `RegistryObject`
193
+ - `RepositoryItemRef`
194
+ - `QueryResponse`
195
+ - `Classification`
196
+
197
+ Усі класи мають однаковий базовий контракт:
198
+ - `element` — повертає `etree._Element` (або `ValueError`, якщо елемент ще не створено)
199
+ - `text` — серіалізований XML (`bytes`)
200
+ - `create_element(...)` — будує XML елемент і повертає `self` (chain-style)
201
+
202
+ ```python
203
+ from pyRegRep4.RIMElement import RepositoryItemRef, QueryResponse
204
+
205
+ ref = RepositoryItemRef().create_element(
206
+ "https://example.org/document.xml",
207
+ "Document",
208
+ )
209
+ print(ref.text)
210
+
211
+ response = QueryResponse().create_element(
212
+ "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success",
213
+ "req-1",
214
+ )
215
+ print(response.element.tag)
216
+ ```
217
+
218
+ ---
219
+
187
220
  ### Функція `deep_get()` (`pyRegRep4.utils`)
188
221
 
189
222
  ```python
@@ -236,7 +269,7 @@ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
236
269
  ```
237
270
  pyRegRep/
238
271
  ├── pyRegRep4/
239
- │ ├── __init__.py # Експорт: get_slot та типи слотів
272
+ │ ├── __init__.py # Експорт: get_slot, deep_get, Parsing, serialize_any_value_type
240
273
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
241
274
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
242
275
  │ ├── utils.py # deep_get() для вкладених словників
@@ -323,4 +356,4 @@ MIT License — див. файл [LICENSE](LICENSE)
323
356
 
324
357
  ---
325
358
 
326
- **Версія:** 12 · **Оновлено:** 2026-04-12
359
+ **Версія:** 13 · **Оновлено:** 2026-04-14
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyRegRep
3
- Version: 12
3
+ Version: 13
4
4
  Summary: Your package description
5
5
  Author: Andrey Shapovalov
6
6
  Author-email: mt.andrey@gmail.com
@@ -28,6 +28,7 @@ Dynamic: license-file
28
28
  - ✅ Обробка всіх типів значень: Boolean, String, Integer, DateTime, Collection, InternationalString, AnyValue
29
29
  - ✅ Серіалізація даних у зручний Python-формат (`dict`)
30
30
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
31
+ - ✅ Builder-класи для елементів `RegistryObject`, `RepositoryItemRef`, `QueryResponse`, `Classification`
31
32
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
32
33
  - ✅ Підтримка вкладених колекцій та складних структур
33
34
  - ✅ Безпечний доступ до вкладених даних через `deep_get()`
@@ -198,6 +199,38 @@ except ValueError as e:
198
199
 
199
200
  ---
200
201
 
202
+ ### Builder-класи XML елементів (`pyRegRep4.RIMElement`)
203
+
204
+ Публічні класи для побудови типових елементів RIM/query:
205
+
206
+ - `RegistryObject`
207
+ - `RepositoryItemRef`
208
+ - `QueryResponse`
209
+ - `Classification`
210
+
211
+ Усі класи мають однаковий базовий контракт:
212
+ - `element` — повертає `etree._Element` (або `ValueError`, якщо елемент ще не створено)
213
+ - `text` — серіалізований XML (`bytes`)
214
+ - `create_element(...)` — будує XML елемент і повертає `self` (chain-style)
215
+
216
+ ```python
217
+ from pyRegRep4.RIMElement import RepositoryItemRef, QueryResponse
218
+
219
+ ref = RepositoryItemRef().create_element(
220
+ "https://example.org/document.xml",
221
+ "Document",
222
+ )
223
+ print(ref.text)
224
+
225
+ response = QueryResponse().create_element(
226
+ "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success",
227
+ "req-1",
228
+ )
229
+ print(response.element.tag)
230
+ ```
231
+
232
+ ---
233
+
201
234
  ### Функція `deep_get()` (`pyRegRep4.utils`)
202
235
 
203
236
  ```python
@@ -250,7 +283,7 @@ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
250
283
  ```
251
284
  pyRegRep/
252
285
  ├── pyRegRep4/
253
- │ ├── __init__.py # Експорт: get_slot та типи слотів
286
+ │ ├── __init__.py # Експорт: get_slot, deep_get, Parsing, serialize_any_value_type
254
287
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
255
288
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
256
289
  │ ├── utils.py # deep_get() для вкладених словників
@@ -337,4 +370,4 @@ MIT License — див. файл [LICENSE](LICENSE)
337
370
 
338
371
  ---
339
372
 
340
- **Версія:** 12 · **Оновлено:** 2026-04-12
373
+ **Версія:** 13 · **Оновлено:** 2026-04-14
@@ -13,6 +13,7 @@ class NS:
13
13
  "rs": "urn:oasis:names:tc:ebxml-regrep:xsd:rs:4.0",
14
14
  "xsi": "http://www.w3.org/2001/XMLSchema-instance",
15
15
  "xsd": "http://www.w3.org/2001/XMLSchema",
16
+ "xlink": "http://www.w3.org/1999/xlink",
16
17
  "xml": "http://www.w3.org/XML/1998/namespace",
17
18
  }
18
19
 
@@ -1,6 +1,7 @@
1
1
  import datetime
2
2
  import logging
3
- from typing import Any
3
+ from abc import ABC, abstractmethod
4
+ from typing import Any, Callable
4
5
 
5
6
  from lxml import etree
6
7
 
@@ -8,14 +9,41 @@ from pyRegRep4.NS import NS
8
9
 
9
10
  _logger = logging.getLogger(__name__)
10
11
 
12
+ __all__ = [
13
+ "get_slot",
14
+ "RegistryObject",
15
+ "RepositoryItemRef",
16
+ "QueryResponse",
17
+ "Classification"
18
+ ]
19
+
20
+
21
+ class _ElementContainer(NS):
22
+ """Internal base for simple classes that wrap a single XML element."""
23
+
24
+ def __init__(self) -> None:
25
+ super().__init__()
26
+ self._element: etree._Element | None = None
27
+
28
+ @property
29
+ def element(self) -> etree._Element:
30
+ if self._element is None:
31
+ raise ValueError("XML element is not initialized")
32
+ return self._element
33
+
34
+ @property
35
+ def text(self) -> bytes:
36
+ return etree.tostring(self.element)
37
+
38
+
39
+ class Xml(ABC, _ElementContainer):
40
+ """Base class for slot-like XML objects that carry value and name."""
11
41
 
12
- class Xml(NS):
13
42
  def __init__(self, value: Any):
14
43
  super().__init__()
15
44
  self._name: str = ""
16
45
  self.value: Any = value
17
- self._element: etree._Element | None = None
18
- self._create_element()
46
+ self.create_element()
19
47
 
20
48
  @property
21
49
  def name(self) -> str:
@@ -25,24 +53,15 @@ class Xml(NS):
25
53
  def name(self, value: str) -> None:
26
54
  self._name = value
27
55
  if self._element is not None:
28
- self._create_element()
56
+ self.create_element()
29
57
 
30
- def _create_element(self):
58
+ @abstractmethod
59
+ def create_element(self):
31
60
  ...
32
61
 
33
- @property
34
- def element(self) -> etree._Element:
35
- if self._element is None:
36
- raise ValueError("XML element is not initialized")
37
- return self._element
38
-
39
- @property
40
- def text(self) -> bytes:
41
- return etree.tostring(self.element)
42
-
43
62
 
44
63
  class _BooleanValueType(Xml):
45
- def _create_element(self):
64
+ def create_element(self):
46
65
  self._element = etree.Element(
47
66
  self._tname("rim", "Slot"), nsmap=self._ns,
48
67
  attrib={"name": self.name}
@@ -56,7 +75,7 @@ class _BooleanValueType(Xml):
56
75
 
57
76
 
58
77
  class _StringValueType(Xml):
59
- def _create_element(self):
78
+ def create_element(self):
60
79
  self._element = etree.Element(
61
80
  self._tname("rim", "Slot"), nsmap=self._ns,
62
81
  attrib={"name": self.name}
@@ -70,7 +89,7 @@ class _StringValueType(Xml):
70
89
 
71
90
 
72
91
  class _TimeStamp(Xml):
73
- def _create_element(self):
92
+ def create_element(self):
74
93
  self._element = etree.Element(
75
94
  self._tname("rim", "Slot"), nsmap=self._ns,
76
95
  attrib={"name": self.name}
@@ -87,7 +106,7 @@ class _TimeStamp(Xml):
87
106
 
88
107
 
89
108
  class _CollectionValueType(Xml):
90
- def _create_element(self):
109
+ def create_element(self):
91
110
  self._element = etree.Element(
92
111
  self._tname("rim", "Slot"), nsmap=self._ns,
93
112
  attrib={"name": self.name}
@@ -110,7 +129,7 @@ class _CollectionValueType(Xml):
110
129
 
111
130
 
112
131
  class _AnyValueType(Xml):
113
- def _create_element(self):
132
+ def create_element(self):
114
133
  self._element = etree.Element(
115
134
  self._tname("rim", "Slot"), nsmap=self._ns,
116
135
  attrib={"name": self.name}
@@ -124,7 +143,7 @@ class _AnyValueType(Xml):
124
143
 
125
144
 
126
145
  class _InternationalStringValueType(Xml):
127
- def _create_element(self):
146
+ def create_element(self):
128
147
  self._element = etree.Element(
129
148
  self._tname("rim", "Slot"), nsmap=self._ns,
130
149
  attrib={"name": self.name}
@@ -226,7 +245,7 @@ def get_slot(name: str, slot_type: str, value: Any) -> Xml:
226
245
  ... except ValueError as e:
227
246
  ... print(f"Error: {e}")
228
247
  """
229
- slot_type_map = {
248
+ slot_type_map: dict[str, Callable[[Any], Xml]] = {
230
249
  "StringValueType": _StringValueType,
231
250
  "BooleanValueType": _BooleanValueType,
232
251
  "DateTimeValueType": _TimeStamp,
@@ -242,3 +261,64 @@ def get_slot(name: str, slot_type: str, value: Any) -> Xml:
242
261
  slot = slot_class(value)
243
262
  slot.name = name
244
263
  return slot
264
+
265
+
266
+ class RegistryObject(_ElementContainer):
267
+ """Builder for rim:RegistryObject elements."""
268
+
269
+ def create_element(self, type: str, id: str):
270
+ self._element = etree.Element(
271
+ self._tname("rim", "RegistryObject"),
272
+ nsmap=self._ns,
273
+ attrib={
274
+ self._tname("xsi", "type"): type,
275
+ "id": id
276
+ }
277
+ )
278
+ return self
279
+
280
+
281
+ class RepositoryItemRef(_ElementContainer):
282
+ """Builder for rim:RepositoryItemRef elements."""
283
+
284
+ def create_element(self, href: str, title: str | None = None):
285
+ attr = {self._tname("xlink", "href"): href}
286
+ if title is not None:
287
+ attr["title"] = title
288
+
289
+ self._element = etree.Element(
290
+ self._tname("rim", "RepositoryItemRef"),
291
+ nsmap=self._ns,
292
+ attrib=attr
293
+ )
294
+ return self
295
+
296
+
297
+ class QueryResponse(_ElementContainer):
298
+ """Builder for query:QueryResponse elements."""
299
+
300
+ def create_element(self, status: str, request_id: str):
301
+ self._element = etree.Element(
302
+ self._tname("query", "QueryResponse"), nsmap=self._ns,
303
+ attrib={
304
+ 'status': status,
305
+ 'requestId': request_id,
306
+ }
307
+ )
308
+ return self
309
+
310
+
311
+ class Classification(_ElementContainer):
312
+ """Builder for rim:Classification elements."""
313
+
314
+ def create_element(self, id: str, classification_scheme: str, classification_node: str):
315
+ self._element = etree.Element(
316
+ self._tname("rim", "Classification"),
317
+ nsmap=self._ns,
318
+ attrib={
319
+ "id": id,
320
+ "classificationScheme": classification_scheme,
321
+ "classificationNode": classification_node
322
+ }
323
+ )
324
+ return self
@@ -10,29 +10,26 @@ Main Components:
10
10
  """
11
11
 
12
12
  from pyRegRep4.RIMElement import (
13
+ Classification,
14
+ QueryResponse,
15
+ RegistryObject,
16
+ RepositoryItemRef,
13
17
  get_slot,
14
- Xml,
15
- _StringValueType,
16
- _BooleanValueType,
17
- _TimeStamp,
18
- _CollectionValueType,
19
- _AnyValueType,
20
- _InternationalStringValueType,
21
18
  )
22
19
  from pyRegRep4.utils import deep_get
20
+ from pyRegRep4.RIMParsing import Parsing, serialize_any_value_type
23
21
 
24
22
  __all__ = [
25
23
  "get_slot",
26
- "Xml",
27
- "_StringValueType",
28
- "_BooleanValueType",
29
- "_TimeStamp",
30
- "_CollectionValueType",
31
- "_AnyValueType",
32
- "_InternationalStringValueType",
24
+ "RepositoryItemRef",
25
+ "RegistryObject",
26
+ "Classification",
27
+ "QueryResponse",
33
28
  "deep_get",
29
+ "Parsing",
30
+ "serialize_any_value_type",
34
31
  ]
35
32
 
36
- __version__ = "12"
33
+ __version__ = "13"
37
34
  __author__ = "Andrey Shapovalov"
38
35
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyRegRep"
7
- version = "12"
7
+ version = "13"
8
8
  description = "Your package description"
9
9
  authors = [{ name="Andrey Shapovalov" }]
10
10
  readme = "README.md"
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="pyRegRep",
5
- version="12",
5
+ version="13",
6
6
  description="Бібліотека для роботи з реєстрами та репозитаріями в Україні",
7
7
  packages=find_packages(),
8
8
  license="MIT",
@@ -18,6 +18,10 @@ from pyRegRep4.RIMElement import (
18
18
  _CollectionValueType,
19
19
  _AnyValueType,
20
20
  _InternationalStringValueType,
21
+ RegistryObject,
22
+ RepositoryItemRef,
23
+ QueryResponse,
24
+ Classification,
21
25
  )
22
26
 
23
27
 
@@ -468,3 +472,38 @@ class TestSlotElementGeneration:
468
472
  assert slot.element.attrib.get("name") == test_name
469
473
 
470
474
 
475
+ class TestSimpleElementContainers:
476
+ """Regression tests for classes sharing common element/text behavior."""
477
+
478
+ @pytest.mark.parametrize(
479
+ "obj",
480
+ [RegistryObject(), RepositoryItemRef(), QueryResponse(), Classification()],
481
+ )
482
+ def test_element_raises_before_create(self, obj):
483
+ with pytest.raises(ValueError, match="XML element is not initialized"):
484
+ _ = obj.element
485
+
486
+ def test_registry_object_create_and_serialize(self):
487
+ obj = RegistryObject()
488
+ assert obj.create_element("rim:ExtrinsicObject", "urn:uuid:test") is obj
489
+ assert b"RegistryObject" in obj.text
490
+
491
+ def test_repository_item_ref_create_and_serialize(self):
492
+ obj = RepositoryItemRef()
493
+ assert obj.create_element("https://example.org/doc.xml", "Doc") is obj
494
+ assert b"RepositoryItemRef" in obj.text
495
+ assert b"xlink:href" in obj.text
496
+
497
+ def test_query_response_create_and_serialize(self):
498
+ obj = QueryResponse()
499
+ assert obj.create_element(
500
+ "urn:oasis:names:tc:ebxml-regrep:ResponseStatusType:Success", "req-1"
501
+ ) is obj
502
+ assert b"QueryResponse" in obj.text
503
+
504
+ def test_classification_create_and_serialize(self):
505
+ obj = Classification()
506
+ assert obj.create_element("urn:uuid:cls", "urn:scheme", "Annex") is obj
507
+ assert b"Classification" in obj.text
508
+
509
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes