pyRegRep 10__tar.gz → 12__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,12 +1,14 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyRegRep
3
- Version: 10
3
+ Version: 12
4
4
  Summary: Your package description
5
5
  Author: Andrey Shapovalov
6
6
  Author-email: mt.andrey@gmail.com
7
7
  Requires-Python: >=3.10
8
8
  Description-Content-Type: text/markdown
9
9
  License-File: LICENSE
10
+ Requires-Dist: lxml>=5.2.1
11
+ Requires-Dist: xmltodict>=0.13.0
10
12
  Dynamic: author-email
11
13
  Dynamic: license-file
12
14
 
@@ -28,6 +30,7 @@ Dynamic: license-file
28
30
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
29
31
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
30
32
  - ✅ Підтримка вкладених колекцій та складних структур
33
+ - ✅ Безпечний доступ до вкладених даних через `deep_get()`
31
34
 
32
35
  ## Вимоги
33
36
 
@@ -44,11 +47,10 @@ pip install pyRegRep
44
47
 
45
48
  # З локального джерела (editable)
46
49
  pip install -e .
47
-
48
- # Залежності вручну
49
- pip install -r requirements.txt
50
50
  ```
51
51
 
52
+ Під час встановлення через `pip install pyRegRep` або `pip install -e .` runtime-залежності (`lxml`, `xmltodict`) встановлюються автоматично.
53
+
52
54
  ## Швидкий старт
53
55
 
54
56
  ### Парсування XML документу
@@ -67,6 +69,12 @@ print(parser.serialize())
67
69
 
68
70
  # Серіалізація з обробкою AnyValueType в dict
69
71
  print(parser.serialize(any_type=True))
72
+
73
+ from pyRegRep4 import deep_get
74
+
75
+ # Безпечний доступ до вкладених ключів
76
+ spec_id = deep_get(parser.serialize(), "doc", "SpecificationIdentifier", default="unknown")
77
+ print(spec_id)
70
78
  ```
71
79
 
72
80
  ### Програмне створення RIM-слотів
@@ -190,6 +198,43 @@ except ValueError as e:
190
198
 
191
199
  ---
192
200
 
201
+ ### Функція `deep_get()` (`pyRegRep4.utils`)
202
+
203
+ ```python
204
+ deep_get(data: dict, *keys, default=None)
205
+ ```
206
+
207
+ Безпечно дістає значення з вкладеного `dict` за послідовністю ключів.
208
+
209
+ | Параметр | Тип | Опис |
210
+ |----------|-----|------|
211
+ | `data` | `dict` | Джерело даних |
212
+ | `*keys` | `Any` | Шлях ключів для проходу по вкладеному словнику |
213
+ | `default` | `Any` | Значення за замовчуванням, якщо шлях не знайдено |
214
+
215
+ **Поведінка:**
216
+ - якщо на будь-якому кроці значення не є `dict` — повертається `default`
217
+ - якщо кінцеве значення `None` — повертається `default`
218
+ - якщо `keys` не передані — повертається `data`
219
+
220
+ ```python
221
+ from pyRegRep4 import deep_get
222
+
223
+ data = {
224
+ "doc": {
225
+ "Procedure": [{"lang": "en", "value": "GetBirthCertificate"}]
226
+ }
227
+ }
228
+
229
+ value = deep_get(data, "doc", "Procedure", 0, "value", default="n/a")
230
+ print(value) # n/a (бо deep_get працює тільки з dict-ланцюжком)
231
+
232
+ procedure = deep_get(data, "doc", "Procedure", default=[])
233
+ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
234
+ ```
235
+
236
+ ---
237
+
193
238
  ### Клас `NS` (`pyRegRep4.NS`)
194
239
 
195
240
  Базовий клас для управління RIM namespace. Надає метод `_tname(prefix, localname)` для генерування кваліфікованих імен тегів у нотації Clark.
@@ -208,11 +253,13 @@ pyRegRep/
208
253
  │ ├── __init__.py # Експорт: get_slot та типи слотів
209
254
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
210
255
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
256
+ │ ├── utils.py # deep_get() для вкладених словників
211
257
  │ └── NS.py # Базовий клас для namespace
212
258
  ├── tests/
213
259
  │ ├── conftest.py # sys.path для CI
214
260
  │ ├── test_rim_parsing.py # Тести парсера
215
261
  │ ├── test_rim_element.py # Тести get_slot() та типів слотів
262
+ │ ├── test_utils.py # Тести deep_get()
216
263
  │ ├── EDM_Ferst_Request.xml
217
264
  │ ├── EDM_Ferst_Response.xml
218
265
  │ ├── EDM_Second_Request.xml
@@ -290,4 +337,4 @@ MIT License — див. файл [LICENSE](LICENSE)
290
337
 
291
338
  ---
292
339
 
293
- **Версія:** 10 · **Оновлено:** 2026-03-11
340
+ **Версія:** 12 · **Оновлено:** 2026-04-12
@@ -1,15 +1,3 @@
1
- Metadata-Version: 2.4
2
- Name: pyRegRep
3
- Version: 10
4
- Summary: Your package description
5
- Author: Andrey Shapovalov
6
- Author-email: mt.andrey@gmail.com
7
- Requires-Python: >=3.10
8
- Description-Content-Type: text/markdown
9
- License-File: LICENSE
10
- Dynamic: author-email
11
- Dynamic: license-file
12
-
13
1
  # pyRegRep
14
2
 
15
3
  Бібліотека Python для парсування та обробки XML документів у форматі RIM (Registry Information Model) / ebXML.
@@ -28,6 +16,7 @@ Dynamic: license-file
28
16
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
29
17
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
30
18
  - ✅ Підтримка вкладених колекцій та складних структур
19
+ - ✅ Безпечний доступ до вкладених даних через `deep_get()`
31
20
 
32
21
  ## Вимоги
33
22
 
@@ -44,11 +33,10 @@ pip install pyRegRep
44
33
 
45
34
  # З локального джерела (editable)
46
35
  pip install -e .
47
-
48
- # Залежності вручну
49
- pip install -r requirements.txt
50
36
  ```
51
37
 
38
+ Під час встановлення через `pip install pyRegRep` або `pip install -e .` runtime-залежності (`lxml`, `xmltodict`) встановлюються автоматично.
39
+
52
40
  ## Швидкий старт
53
41
 
54
42
  ### Парсування XML документу
@@ -67,6 +55,12 @@ print(parser.serialize())
67
55
 
68
56
  # Серіалізація з обробкою AnyValueType в dict
69
57
  print(parser.serialize(any_type=True))
58
+
59
+ from pyRegRep4 import deep_get
60
+
61
+ # Безпечний доступ до вкладених ключів
62
+ spec_id = deep_get(parser.serialize(), "doc", "SpecificationIdentifier", default="unknown")
63
+ print(spec_id)
70
64
  ```
71
65
 
72
66
  ### Програмне створення RIM-слотів
@@ -190,6 +184,43 @@ except ValueError as e:
190
184
 
191
185
  ---
192
186
 
187
+ ### Функція `deep_get()` (`pyRegRep4.utils`)
188
+
189
+ ```python
190
+ deep_get(data: dict, *keys, default=None)
191
+ ```
192
+
193
+ Безпечно дістає значення з вкладеного `dict` за послідовністю ключів.
194
+
195
+ | Параметр | Тип | Опис |
196
+ |----------|-----|------|
197
+ | `data` | `dict` | Джерело даних |
198
+ | `*keys` | `Any` | Шлях ключів для проходу по вкладеному словнику |
199
+ | `default` | `Any` | Значення за замовчуванням, якщо шлях не знайдено |
200
+
201
+ **Поведінка:**
202
+ - якщо на будь-якому кроці значення не є `dict` — повертається `default`
203
+ - якщо кінцеве значення `None` — повертається `default`
204
+ - якщо `keys` не передані — повертається `data`
205
+
206
+ ```python
207
+ from pyRegRep4 import deep_get
208
+
209
+ data = {
210
+ "doc": {
211
+ "Procedure": [{"lang": "en", "value": "GetBirthCertificate"}]
212
+ }
213
+ }
214
+
215
+ value = deep_get(data, "doc", "Procedure", 0, "value", default="n/a")
216
+ print(value) # n/a (бо deep_get працює тільки з dict-ланцюжком)
217
+
218
+ procedure = deep_get(data, "doc", "Procedure", default=[])
219
+ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
220
+ ```
221
+
222
+ ---
223
+
193
224
  ### Клас `NS` (`pyRegRep4.NS`)
194
225
 
195
226
  Базовий клас для управління RIM namespace. Надає метод `_tname(prefix, localname)` для генерування кваліфікованих імен тегів у нотації Clark.
@@ -208,11 +239,13 @@ pyRegRep/
208
239
  │ ├── __init__.py # Експорт: get_slot та типи слотів
209
240
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
210
241
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
242
+ │ ├── utils.py # deep_get() для вкладених словників
211
243
  │ └── NS.py # Базовий клас для namespace
212
244
  ├── tests/
213
245
  │ ├── conftest.py # sys.path для CI
214
246
  │ ├── test_rim_parsing.py # Тести парсера
215
247
  │ ├── test_rim_element.py # Тести get_slot() та типів слотів
248
+ │ ├── test_utils.py # Тести deep_get()
216
249
  │ ├── EDM_Ferst_Request.xml
217
250
  │ ├── EDM_Ferst_Response.xml
218
251
  │ ├── EDM_Second_Request.xml
@@ -290,4 +323,4 @@ MIT License — див. файл [LICENSE](LICENSE)
290
323
 
291
324
  ---
292
325
 
293
- **Версія:** 10 · **Оновлено:** 2026-03-11
326
+ **Версія:** 12 · **Оновлено:** 2026-04-12
@@ -1,3 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: pyRegRep
3
+ Version: 12
4
+ Summary: Your package description
5
+ Author: Andrey Shapovalov
6
+ Author-email: mt.andrey@gmail.com
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: lxml>=5.2.1
11
+ Requires-Dist: xmltodict>=0.13.0
12
+ Dynamic: author-email
13
+ Dynamic: license-file
14
+
1
15
  # pyRegRep
2
16
 
3
17
  Бібліотека Python для парсування та обробки XML документів у форматі RIM (Registry Information Model) / ebXML.
@@ -16,6 +30,7 @@
16
30
  - ✅ Фабрика слотів `get_slot()` — програмне створення RIM-слотів за типом
17
31
  - ✅ Серіалізація `AnyValueType` через `xmltodict` (параметр `any_type=True`)
18
32
  - ✅ Підтримка вкладених колекцій та складних структур
33
+ - ✅ Безпечний доступ до вкладених даних через `deep_get()`
19
34
 
20
35
  ## Вимоги
21
36
 
@@ -32,11 +47,10 @@ pip install pyRegRep
32
47
 
33
48
  # З локального джерела (editable)
34
49
  pip install -e .
35
-
36
- # Залежності вручну
37
- pip install -r requirements.txt
38
50
  ```
39
51
 
52
+ Під час встановлення через `pip install pyRegRep` або `pip install -e .` runtime-залежності (`lxml`, `xmltodict`) встановлюються автоматично.
53
+
40
54
  ## Швидкий старт
41
55
 
42
56
  ### Парсування XML документу
@@ -55,6 +69,12 @@ print(parser.serialize())
55
69
 
56
70
  # Серіалізація з обробкою AnyValueType в dict
57
71
  print(parser.serialize(any_type=True))
72
+
73
+ from pyRegRep4 import deep_get
74
+
75
+ # Безпечний доступ до вкладених ключів
76
+ spec_id = deep_get(parser.serialize(), "doc", "SpecificationIdentifier", default="unknown")
77
+ print(spec_id)
58
78
  ```
59
79
 
60
80
  ### Програмне створення RIM-слотів
@@ -178,6 +198,43 @@ except ValueError as e:
178
198
 
179
199
  ---
180
200
 
201
+ ### Функція `deep_get()` (`pyRegRep4.utils`)
202
+
203
+ ```python
204
+ deep_get(data: dict, *keys, default=None)
205
+ ```
206
+
207
+ Безпечно дістає значення з вкладеного `dict` за послідовністю ключів.
208
+
209
+ | Параметр | Тип | Опис |
210
+ |----------|-----|------|
211
+ | `data` | `dict` | Джерело даних |
212
+ | `*keys` | `Any` | Шлях ключів для проходу по вкладеному словнику |
213
+ | `default` | `Any` | Значення за замовчуванням, якщо шлях не знайдено |
214
+
215
+ **Поведінка:**
216
+ - якщо на будь-якому кроці значення не є `dict` — повертається `default`
217
+ - якщо кінцеве значення `None` — повертається `default`
218
+ - якщо `keys` не передані — повертається `data`
219
+
220
+ ```python
221
+ from pyRegRep4 import deep_get
222
+
223
+ data = {
224
+ "doc": {
225
+ "Procedure": [{"lang": "en", "value": "GetBirthCertificate"}]
226
+ }
227
+ }
228
+
229
+ value = deep_get(data, "doc", "Procedure", 0, "value", default="n/a")
230
+ print(value) # n/a (бо deep_get працює тільки з dict-ланцюжком)
231
+
232
+ procedure = deep_get(data, "doc", "Procedure", default=[])
233
+ print(procedure) # [{"lang": "en", "value": "GetBirthCertificate"}]
234
+ ```
235
+
236
+ ---
237
+
181
238
  ### Клас `NS` (`pyRegRep4.NS`)
182
239
 
183
240
  Базовий клас для управління RIM namespace. Надає метод `_tname(prefix, localname)` для генерування кваліфікованих імен тегів у нотації Clark.
@@ -196,11 +253,13 @@ pyRegRep/
196
253
  │ ├── __init__.py # Експорт: get_slot та типи слотів
197
254
  │ ├── RIMElement.py # Класи слотів + фабрика get_slot()
198
255
  │ ├── RIMParsing.py # Парсер Parsing + serialize()
256
+ │ ├── utils.py # deep_get() для вкладених словників
199
257
  │ └── NS.py # Базовий клас для namespace
200
258
  ├── tests/
201
259
  │ ├── conftest.py # sys.path для CI
202
260
  │ ├── test_rim_parsing.py # Тести парсера
203
261
  │ ├── test_rim_element.py # Тести get_slot() та типів слотів
262
+ │ ├── test_utils.py # Тести deep_get()
204
263
  │ ├── EDM_Ferst_Request.xml
205
264
  │ ├── EDM_Ferst_Response.xml
206
265
  │ ├── EDM_Second_Request.xml
@@ -278,4 +337,4 @@ MIT License — див. файл [LICENSE](LICENSE)
278
337
 
279
338
  ---
280
339
 
281
- **Версія:** 10 · **Оновлено:** 2026-03-11
340
+ **Версія:** 12 · **Оновлено:** 2026-04-12
@@ -5,11 +5,14 @@ setup.py
5
5
  pyRegRep.egg-info/PKG-INFO
6
6
  pyRegRep.egg-info/SOURCES.txt
7
7
  pyRegRep.egg-info/dependency_links.txt
8
+ pyRegRep.egg-info/requires.txt
8
9
  pyRegRep.egg-info/top_level.txt
9
10
  pyRegRep4/NS.py
10
11
  pyRegRep4/RIMElement.py
11
12
  pyRegRep4/RIMParsing.py
12
13
  pyRegRep4/__init__.py
14
+ pyRegRep4/utils.py
13
15
  tests/test_get_slot_simple.py
14
16
  tests/test_rim_element.py
15
- tests/test_rim_parsing.py
17
+ tests/test_rim_parsing.py
18
+ tests/test_utils.py
@@ -0,0 +1,2 @@
1
+ lxml>=5.2.1
2
+ xmltodict>=0.13.0
@@ -73,12 +73,20 @@ class Parsing:
73
73
  # Витягування основних елементів
74
74
  try:
75
75
  self.query = self.doc.find(".//query:Query", namespaces=self._ns)
76
- self.exception = self.doc.find(".//rs:Exception", namespaces=self._ns)
77
- self.objects = self.doc.findall(".//rim:RegistryObject", namespaces=self._ns)
78
- except KeyError as e:
76
+ except Exception as e:
79
77
  _logger.warning(f"Namespace не знайдено: {e}")
80
78
  self.query = None
79
+
80
+ try:
81
+ self.exception = self.doc.find(".//rs:Exception", namespaces=self._ns)
82
+ except Exception as e:
83
+ _logger.warning(f"Namespace не знайдено: {e}")
81
84
  self.exception = None
85
+
86
+ try:
87
+ self.objects = self.doc.findall(".//rim:RegistryObject", namespaces=self._ns)
88
+ except Exception as e:
89
+ _logger.warning(f"Namespace не знайдено: {e}")
82
90
  self.objects = []
83
91
 
84
92
  # Кешований результат
@@ -19,6 +19,7 @@ from pyRegRep4.RIMElement import (
19
19
  _AnyValueType,
20
20
  _InternationalStringValueType,
21
21
  )
22
+ from pyRegRep4.utils import deep_get
22
23
 
23
24
  __all__ = [
24
25
  "get_slot",
@@ -29,8 +30,9 @@ __all__ = [
29
30
  "_CollectionValueType",
30
31
  "_AnyValueType",
31
32
  "_InternationalStringValueType",
33
+ "deep_get",
32
34
  ]
33
35
 
34
- __version__ = "10"
36
+ __version__ = "12"
35
37
  __author__ = "Andrey Shapovalov"
36
38
 
@@ -0,0 +1,23 @@
1
+ """Utility helpers for working with nested dictionaries."""
2
+
3
+ from typing import Any
4
+
5
+
6
+ def deep_get(data: dict[Any, Any], *keys: str, default: Any = None) -> Any:
7
+ """Safely read nested keys from a dictionary.
8
+
9
+ Args:
10
+ data: Source dictionary.
11
+ *keys: Sequence of keys to traverse.
12
+ default: Value returned when the key path is missing or the intermediate value is not a dict.
13
+
14
+ Returns:
15
+ Value by key path or "default" when the path cannot be resolved.
16
+ """
17
+ current: Any = data
18
+ for key in keys:
19
+ if not isinstance(current, dict):
20
+ return default
21
+ current = current.get(key)
22
+ return current if current is not None else default
23
+
@@ -4,12 +4,15 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "pyRegRep"
7
- version = "10"
7
+ version = "12"
8
8
  description = "Your package description"
9
9
  authors = [{ name="Andrey Shapovalov" }]
10
10
  readme = "README.md"
11
11
  requires-python = ">=3.10"
12
- dependencies = []
12
+ dependencies = [
13
+ "lxml>=5.2.1",
14
+ "xmltodict>=0.13.0",
15
+ ]
13
16
 
14
17
  [tool.pytest.ini_options]
15
18
  pythonpath = ["."]
@@ -2,12 +2,15 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="pyRegRep",
5
- version="10",
5
+ version="12",
6
6
  description="Бібліотека для роботи з реєстрами та репозитаріями в Україні",
7
7
  packages=find_packages(),
8
8
  license="MIT",
9
9
  author="Andrii Shapovalov",
10
10
  author_email="mt.andrey@gmail.com",
11
11
  include_package_data=True,
12
- install_requires=[],
12
+ install_requires=[
13
+ "lxml>=5.2.1",
14
+ "xmltodict>=0.13.0",
15
+ ],
13
16
  )
@@ -0,0 +1,33 @@
1
+ """Unit tests for helper utilities."""
2
+
3
+ from pyRegRep4 import deep_get
4
+
5
+
6
+ class TestDeepGet:
7
+ """Tests for deep_get utility function."""
8
+
9
+ def test_returns_nested_value(self):
10
+ data = {"doc": {"meta": {"id": "ABC-123"}}}
11
+
12
+ assert deep_get(data, "doc", "meta", "id") == "ABC-123"
13
+
14
+ def test_returns_default_when_key_missing(self):
15
+ data = {"doc": {"meta": {"id": "ABC-123"}}}
16
+
17
+ assert deep_get(data, "doc", "meta", "missing", default="n/a") == "n/a"
18
+
19
+ def test_returns_default_when_intermediate_is_not_dict(self):
20
+ data = {"doc": {"meta": "plain-text"}}
21
+
22
+ assert deep_get(data, "doc", "meta", "id", default=None) is None
23
+
24
+ def test_returns_default_when_value_is_none(self):
25
+ data = {"doc": {"meta": {"id": None}}}
26
+
27
+ assert deep_get(data, "doc", "meta", "id", default="fallback") == "fallback"
28
+
29
+ def test_returns_root_data_when_keys_not_provided(self):
30
+ data = {"doc": {"meta": {"id": "ABC-123"}}}
31
+
32
+ assert deep_get(data) == data
33
+
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes