drb 2.3.4__tar.gz → 2.3.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.
Files changed (102) hide show
  1. {drb-2.3.4/drb.egg-info → drb-2.3.5}/PKG-INFO +1 -1
  2. {drb-2.3.4 → drb-2.3.5}/drb/core/_version.py +3 -3
  3. drb-2.3.5/drb/core/context.py +24 -0
  4. {drb-2.3.4 → drb-2.3.5}/drb/core/node.py +7 -0
  5. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/manager_dao.py +41 -1
  6. {drb-2.3.4 → drb-2.3.5/drb.egg-info}/PKG-INFO +1 -1
  7. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/SOURCES.txt +4 -0
  8. drb-2.3.5/tests/test_manager_get_dao.py +27 -0
  9. drb-2.3.5/tests/test_node_context.py +42 -0
  10. drb-2.3.5/tests/test_topic_descriptor_discovery.py +55 -0
  11. {drb-2.3.4 → drb-2.3.5}/LICENCE.txt +0 -0
  12. {drb-2.3.4 → drb-2.3.5}/MANIFEST.in +0 -0
  13. {drb-2.3.4 → drb-2.3.5}/README.md +0 -0
  14. {drb-2.3.4 → drb-2.3.5}/drb/addons/addon.py +0 -0
  15. {drb-2.3.4 → drb-2.3.5}/drb/core/__init__.py +0 -0
  16. {drb-2.3.4 → drb-2.3.5}/drb/core/cortex_validator.py +0 -0
  17. {drb-2.3.4 → drb-2.3.5}/drb/core/events.py +0 -0
  18. {drb-2.3.4 → drb-2.3.5}/drb/core/factory.py +0 -0
  19. {drb-2.3.4 → drb-2.3.5}/drb/core/impls.py +0 -0
  20. {drb-2.3.4 → drb-2.3.5}/drb/core/item.py +0 -0
  21. {drb-2.3.4 → drb-2.3.5}/drb/core/path.py +0 -0
  22. {drb-2.3.4 → drb-2.3.5}/drb/core/predicate.py +0 -0
  23. {drb-2.3.4 → drb-2.3.5}/drb/core/signature.py +0 -0
  24. {drb-2.3.4 → drb-2.3.5}/drb/drivers/file/__init__.py +0 -0
  25. {drb-2.3.4 → drb-2.3.5}/drb/drivers/file/file.py +0 -0
  26. {drb-2.3.4 → drb-2.3.5}/drb/drivers/xml/__init__.py +0 -0
  27. {drb-2.3.4 → drb-2.3.5}/drb/drivers/xml/factory.py +0 -0
  28. {drb-2.3.4 → drb-2.3.5}/drb/drivers/xml/node.py +0 -0
  29. {drb-2.3.4 → drb-2.3.5}/drb/exceptions/core.py +0 -0
  30. {drb-2.3.4 → drb-2.3.5}/drb/exceptions/file.py +0 -0
  31. {drb-2.3.4 → drb-2.3.5}/drb/keyring/bitwarden/__init__.py +0 -0
  32. {drb-2.3.4 → drb-2.3.5}/drb/keyring/bitwarden/bitwarden.py +0 -0
  33. {drb-2.3.4 → drb-2.3.5}/drb/nodes/abstract_node.py +0 -0
  34. {drb-2.3.4 → drb-2.3.5}/drb/nodes/logical_node.py +0 -0
  35. {drb-2.3.4 → drb-2.3.5}/drb/nodes/mutable_node.py +0 -0
  36. {drb-2.3.4 → drb-2.3.5}/drb/nodes/url_node.py +0 -0
  37. {drb-2.3.4 → drb-2.3.5}/drb/signatures/core.py +0 -0
  38. {drb-2.3.4 → drb-2.3.5}/drb/signatures/xquery.py +0 -0
  39. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/__init__.py +0 -0
  40. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/rdf_dao.py +0 -0
  41. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/topic_dao.py +0 -0
  42. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/topic_schema.yml +0 -0
  43. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/xml_dao.py +0 -0
  44. {drb-2.3.4 → drb-2.3.5}/drb/topics/dao/yaml_dao.py +0 -0
  45. {drb-2.3.4 → drb-2.3.5}/drb/topics/file/__init__.py +0 -0
  46. {drb-2.3.4 → drb-2.3.5}/drb/topics/file/cortex.yml +0 -0
  47. {drb-2.3.4 → drb-2.3.5}/drb/topics/resolver.py +0 -0
  48. {drb-2.3.4 → drb-2.3.5}/drb/topics/topic.py +0 -0
  49. {drb-2.3.4 → drb-2.3.5}/drb/topics/xml/__init__.py +0 -0
  50. {drb-2.3.4 → drb-2.3.5}/drb/topics/xml/cortex.yml +0 -0
  51. {drb-2.3.4 → drb-2.3.5}/drb/utils/__init__.py +0 -0
  52. {drb-2.3.4 → drb-2.3.5}/drb/utils/drb_python_script.py +0 -0
  53. {drb-2.3.4 → drb-2.3.5}/drb/utils/plugins.py +0 -0
  54. {drb-2.3.4 → drb-2.3.5}/drb/utils/url_security.py +0 -0
  55. {drb-2.3.4 → drb-2.3.5}/drb/utils/utils.py +0 -0
  56. {drb-2.3.4 → drb-2.3.5}/drb/xquery/XQueryLexer.py +0 -0
  57. {drb-2.3.4 → drb-2.3.5}/drb/xquery/XQueryParser.py +0 -0
  58. {drb-2.3.4 → drb-2.3.5}/drb/xquery/XQueryParserListener.py +0 -0
  59. {drb-2.3.4 → drb-2.3.5}/drb/xquery/XQueryParserVisitor.py +0 -0
  60. {drb-2.3.4 → drb-2.3.5}/drb/xquery/__init__.py +0 -0
  61. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery.py +0 -0
  62. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_cmd.py +0 -0
  63. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_context.py +0 -0
  64. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_func.py +0 -0
  65. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_item.py +0 -0
  66. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_res_to_string.py +0 -0
  67. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_utils.py +0 -0
  68. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_variable.py +0 -0
  69. {drb-2.3.4 → drb-2.3.5}/drb/xquery/drb_xquery_visitor.py +0 -0
  70. {drb-2.3.4 → drb-2.3.5}/drb/xquery/exceptions.py +0 -0
  71. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/dependency_links.txt +0 -0
  72. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/entry_points.txt +0 -0
  73. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/not-zip-safe +0 -0
  74. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/requires.txt +0 -0
  75. {drb-2.3.4 → drb-2.3.5}/drb.egg-info/top_level.txt +0 -0
  76. {drb-2.3.4 → drb-2.3.5}/pyproject.toml +0 -0
  77. {drb-2.3.4 → drb-2.3.5}/requirements.txt +0 -0
  78. {drb-2.3.4 → drb-2.3.5}/setup.cfg +0 -0
  79. {drb-2.3.4 → drb-2.3.5}/setup.py +0 -0
  80. {drb-2.3.4 → drb-2.3.5}/tests/test_abstract_node.py +0 -0
  81. {drb-2.3.4 → drb-2.3.5}/tests/test_addon.py +0 -0
  82. {drb-2.3.4 → drb-2.3.5}/tests/test_children_unresolved.py +0 -0
  83. {drb-2.3.4 → drb-2.3.5}/tests/test_drb_node_list.py +0 -0
  84. {drb-2.3.4 → drb-2.3.5}/tests/test_drb_python_script.py +0 -0
  85. {drb-2.3.4 → drb-2.3.5}/tests/test_event.py +0 -0
  86. {drb-2.3.4 → drb-2.3.5}/tests/test_factory.py +0 -0
  87. {drb-2.3.4 → drb-2.3.5}/tests/test_factory_resolver.py +0 -0
  88. {drb-2.3.4 → drb-2.3.5}/tests/test_implementation_manager.py +0 -0
  89. {drb-2.3.4 → drb-2.3.5}/tests/test_keyring_bitwarden.py +0 -0
  90. {drb-2.3.4 → drb-2.3.5}/tests/test_logical_node.py +0 -0
  91. {drb-2.3.4 → drb-2.3.5}/tests/test_manager_dao.py +0 -0
  92. {drb-2.3.4 → drb-2.3.5}/tests/test_node_descendant.py +0 -0
  93. {drb-2.3.4 → drb-2.3.5}/tests/test_path.py +0 -0
  94. {drb-2.3.4 → drb-2.3.5}/tests/test_rdf_dao.py +0 -0
  95. {drb-2.3.4 → drb-2.3.5}/tests/test_rdf_dao_multi_url.py +0 -0
  96. {drb-2.3.4 → drb-2.3.5}/tests/test_signatures.py +0 -0
  97. {drb-2.3.4 → drb-2.3.5}/tests/test_topic.py +0 -0
  98. {drb-2.3.4 → drb-2.3.5}/tests/test_url_node.py +0 -0
  99. {drb-2.3.4 → drb-2.3.5}/tests/test_url_security.py +0 -0
  100. {drb-2.3.4 → drb-2.3.5}/tests/test_xml_dao.py +0 -0
  101. {drb-2.3.4 → drb-2.3.5}/tests/test_yaml_dao.py +0 -0
  102. {drb-2.3.4 → drb-2.3.5}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drb
3
- Version: 2.3.4
3
+ Version: 2.3.5
4
4
  Summary: Data Request Broker
5
5
  Author: GAEL Systems
6
6
  Author-email: drb-python@gael.fr
@@ -8,11 +8,11 @@ import json
8
8
 
9
9
  version_json = '''
10
10
  {
11
- "date": "2026-06-19T11:01:35+0000",
11
+ "date": "2026-06-22T12:26:43+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "ad5712117cb18c0a99fbddcf98e59256eafd435e",
15
- "version": "2.3.4"
14
+ "full-revisionid": "262f6e74bc146918a1facd65713ddd8a7cdcbfa1",
15
+ "version": "2.3.5"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,24 @@
1
+ from typing import Dict
2
+
3
+
4
+ class Context:
5
+ """Per-node store of named context buckets.
6
+
7
+ A bucket is a plain ``dict`` keyed by a name (e.g. ``'resolver'`` for
8
+ resolution state, ``'metadata'`` for an add-on's extracted values).
9
+ Buckets are created lazily on first access, so any consumer
10
+ (resolver, add-on) can stash per-node state without the node knowing
11
+ about it:
12
+
13
+ node.context['resolver']['topic'] = topic
14
+ node.context['metadata']['platform'] = 'S2A'
15
+ """
16
+
17
+ def __init__(self):
18
+ self._buckets: Dict[str, dict] = {}
19
+
20
+ def __getitem__(self, name: str) -> dict:
21
+ return self._buckets.setdefault(name, {})
22
+
23
+ def __contains__(self, name: str) -> bool:
24
+ return name in self._buckets
@@ -9,6 +9,7 @@ from deprecated import deprecated
9
9
 
10
10
  from .item import DrbItem
11
11
  from .path import ParsedPath, parse_path
12
+ from .context import Context
12
13
  from .impls import ImplementationManager
13
14
  from ..exceptions.core import DrbException, DrbNotImplementationException
14
15
  from ..utils.utils import get_name_namespace_index, get_name_namespace_value
@@ -42,6 +43,7 @@ class DrbNode(DrbItem, abc.ABC):
42
43
  self.__namespace_aware = None
43
44
  self._attrs = {}
44
45
  self._parent = None
46
+ self._context = Context()
45
47
  self._impl_mng = ImplementationManager()
46
48
  for event_name in self.__event_type_node:
47
49
  self._event_manager.append_event_type(event_name)
@@ -464,5 +466,10 @@ class DrbNode(DrbItem, abc.ABC):
464
466
  return self.has_child(*item)
465
467
  return False
466
468
 
469
+ @property
470
+ def context(self) -> Context:
471
+ """Per-node store of named context buckets (resolver, add-ons...)."""
472
+ return self._context
473
+
467
474
  def __eq__(self, other):
468
475
  return self.path == other.path
@@ -24,6 +24,23 @@ logger = logging.getLogger('DrbTopic')
24
24
  _HTTP_TIMEOUT = (10, 60)
25
25
 
26
26
 
27
+ # Topic descriptor file names looked up in a topic package, in priority
28
+ # order: ontology descriptors (TTL/OWL) first, legacy YAML cortex last. This
29
+ # lets a package ship its topic as TTL (the knowledge-base format) while YAML
30
+ # keeps working during the migration.
31
+ _DESCRIPTOR_NAMES = ('cortex.ttl', 'cortex.owl', 'cortex.yml', 'cortex.yaml')
32
+
33
+
34
+ def _find_topic_descriptor(directory: str):
35
+ """Return the topic descriptor path in ``directory`` (TTL/OWL preferred
36
+ over YAML), or None if none is present."""
37
+ for name in _DESCRIPTOR_NAMES:
38
+ path = os.path.join(directory, name)
39
+ if os.path.exists(path):
40
+ return path
41
+ return None
42
+
43
+
27
44
  def _load_all_drb_topic_dao() -> Dict[uuid.UUID, DrbTopicDao]:
28
45
  """
29
46
  Loads topics defined in the Python context
@@ -39,8 +56,13 @@ def _load_all_drb_topic_dao() -> Dict[uuid.UUID, DrbTopicDao]:
39
56
  logger.warning(f'Invalid entry point {ep.name}: {ex.msg}')
40
57
  continue
41
58
 
59
+ path = _find_topic_descriptor(module.__path__[0])
60
+ if path is None:
61
+ logger.warning(
62
+ f'No topic descriptor (cortex.ttl/.owl/.yml) for {ep.name}')
63
+ continue
64
+
42
65
  try:
43
- path = os.path.join(module.__path__[0], 'cortex.yml')
44
66
  dao = DaoFactory().create(path)
45
67
  topics = dao.read_all()
46
68
  for topic in topics:
@@ -165,6 +187,24 @@ class ManagerDao:
165
187
 
166
188
  raise DrbException('No DrbTopic found')
167
189
 
190
+ def get_dao(self, identifier: uuid.UUID) -> DrbTopicDao:
191
+ """
192
+ Retrieves the DAO that loaded a topic.
193
+
194
+ Lets callers (e.g. add-ons) reach the source of a topic without the
195
+ manager knowing about their concern: for an RDF topic the returned
196
+ ``RDFDao`` exposes ``graph``, the ontology graph it was read from.
197
+
198
+ Parameters:
199
+ identifier (UUID): topic UUID
200
+ Returns:
201
+ DrbTopicDao: the DAO that loaded the topic identified by the
202
+ given UUID.
203
+ """
204
+ if identifier in self.__topic_dao.keys():
205
+ return self.__topic_dao[identifier]
206
+ raise DrbException('No DrbTopic found')
207
+
168
208
  def is_subclass(self, actual: DrbTopic, expected: DrbTopic) -> bool:
169
209
  """
170
210
  Check if a topic is subclass of another.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drb
3
- Version: 2.3.4
3
+ Version: 2.3.5
4
4
  Summary: Data Request Broker
5
5
  Author: GAEL Systems
6
6
  Author-email: drb-python@gael.fr
@@ -16,6 +16,7 @@ drb.egg-info/top_level.txt
16
16
  drb/addons/addon.py
17
17
  drb/core/__init__.py
18
18
  drb/core/_version.py
19
+ drb/core/context.py
19
20
  drb/core/cortex_validator.py
20
21
  drb/core/events.py
21
22
  drb/core/factory.py
@@ -85,12 +86,15 @@ tests/test_implementation_manager.py
85
86
  tests/test_keyring_bitwarden.py
86
87
  tests/test_logical_node.py
87
88
  tests/test_manager_dao.py
89
+ tests/test_manager_get_dao.py
90
+ tests/test_node_context.py
88
91
  tests/test_node_descendant.py
89
92
  tests/test_path.py
90
93
  tests/test_rdf_dao.py
91
94
  tests/test_rdf_dao_multi_url.py
92
95
  tests/test_signatures.py
93
96
  tests/test_topic.py
97
+ tests/test_topic_descriptor_discovery.py
94
98
  tests/test_url_node.py
95
99
  tests/test_url_security.py
96
100
  tests/test_xml_dao.py
@@ -0,0 +1,27 @@
1
+ import unittest
2
+ import uuid
3
+
4
+ from drb.exceptions.core import DrbException
5
+ from drb.topics.dao.manager_dao import ManagerDao
6
+ from drb.topics.dao.topic_dao import DrbTopicDao
7
+
8
+
9
+ class TestManagerGetDao(unittest.TestCase):
10
+ """ManagerDao.get_dao exposes the DAO that loaded a topic."""
11
+
12
+ def test_get_dao_returns_loading_dao(self):
13
+ manager = ManagerDao()
14
+ topics = list(manager.get_all_drb_topics())
15
+ self.assertTrue(topics, 'expected at least one loaded topic')
16
+ dao = manager.get_dao(topics[0].id)
17
+ self.assertIsInstance(dao, DrbTopicDao)
18
+ # The DAO can read back the same topic.
19
+ self.assertEqual(topics[0].id, dao.read(topics[0].id).id)
20
+
21
+ def test_get_dao_unknown_raises(self):
22
+ with self.assertRaises(DrbException):
23
+ ManagerDao().get_dao(uuid.uuid4())
24
+
25
+
26
+ if __name__ == '__main__':
27
+ unittest.main()
@@ -0,0 +1,42 @@
1
+ import unittest
2
+
3
+ from drb.core.context import Context
4
+ from drb.nodes.logical_node import DrbLogicalNode
5
+
6
+
7
+ class TestNodeContext(unittest.TestCase):
8
+ """Per-node context store (recovered from feature_resolution_context)."""
9
+
10
+ def test_buckets_created_lazily(self):
11
+ ctx = Context()
12
+ self.assertNotIn('resolver', ctx)
13
+ bucket = ctx['resolver']
14
+ self.assertEqual({}, bucket)
15
+ self.assertIn('resolver', ctx)
16
+
17
+ def test_bucket_is_persistent_and_mutable(self):
18
+ ctx = Context()
19
+ ctx['resolver']['topic'] = 'X'
20
+ self.assertEqual('X', ctx['resolver']['topic'])
21
+
22
+ def test_buckets_are_independent(self):
23
+ ctx = Context()
24
+ ctx['resolver']['a'] = 1
25
+ ctx['metadata']['b'] = 2
26
+ self.assertEqual({'a': 1}, ctx['resolver'])
27
+ self.assertEqual({'b': 2}, ctx['metadata'])
28
+
29
+ def test_node_exposes_a_context(self):
30
+ node = DrbLogicalNode('n')
31
+ self.assertIsInstance(node.context, Context)
32
+ node.context['resolver']['seen'] = True
33
+ self.assertTrue(node.context['resolver']['seen'])
34
+
35
+ def test_each_node_has_its_own_context(self):
36
+ a, b = DrbLogicalNode('a'), DrbLogicalNode('b')
37
+ a.context['resolver']['x'] = 1
38
+ self.assertNotIn('x', b.context['resolver'])
39
+
40
+
41
+ if __name__ == '__main__':
42
+ unittest.main()
@@ -0,0 +1,55 @@
1
+ import os
2
+ import shutil
3
+ import tempfile
4
+ import unittest
5
+
6
+ from drb.topics.dao.manager_dao import _find_topic_descriptor, DaoFactory
7
+ from drb.topics.dao.rdf_dao import RDFDao
8
+
9
+
10
+ class TestTopicDescriptorDiscovery(unittest.TestCase):
11
+ """A topic package may ship a TTL/OWL descriptor; YAML still works."""
12
+
13
+ _ttl_fixture = os.path.join(
14
+ os.path.dirname(__file__), 'resources', 'landsat-8-topic.ttl')
15
+
16
+ def setUp(self):
17
+ self.dir = tempfile.mkdtemp()
18
+
19
+ def tearDown(self):
20
+ shutil.rmtree(self.dir, ignore_errors=True)
21
+
22
+ def _touch(self, name):
23
+ path = os.path.join(self.dir, name)
24
+ open(path, 'a').close()
25
+ return path
26
+
27
+ def test_prefers_ttl_over_yaml(self):
28
+ self._touch('cortex.yml')
29
+ ttl = self._touch('cortex.ttl')
30
+ self.assertEqual(ttl, _find_topic_descriptor(self.dir))
31
+
32
+ def test_owl_when_no_ttl(self):
33
+ self._touch('cortex.yml')
34
+ owl = self._touch('cortex.owl')
35
+ self.assertEqual(owl, _find_topic_descriptor(self.dir))
36
+
37
+ def test_yaml_fallback(self):
38
+ yml = self._touch('cortex.yml')
39
+ self.assertEqual(yml, _find_topic_descriptor(self.dir))
40
+
41
+ def test_none_when_no_descriptor(self):
42
+ self.assertIsNone(_find_topic_descriptor(self.dir))
43
+
44
+ def test_ttl_descriptor_loads_topics_via_daofactory(self):
45
+ # A package shipping cortex.ttl is loaded through RDFDao and yields
46
+ # topics (the migration target).
47
+ shutil.copy(self._ttl_fixture, os.path.join(self.dir, 'cortex.ttl'))
48
+ descriptor = _find_topic_descriptor(self.dir)
49
+ dao = DaoFactory().create(descriptor)
50
+ self.assertIsInstance(dao, RDFDao)
51
+ self.assertTrue(len(dao.read_all()) > 0)
52
+
53
+
54
+ if __name__ == '__main__':
55
+ unittest.main()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes