drb 2.3.3__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.
- {drb-2.3.3/drb.egg-info → drb-2.3.5}/PKG-INFO +1 -1
- {drb-2.3.3 → drb-2.3.5}/drb/core/_version.py +3 -3
- drb-2.3.5/drb/core/context.py +24 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/node.py +7 -0
- {drb-2.3.3 → drb-2.3.5}/drb/nodes/abstract_node.py +23 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/manager_dao.py +41 -1
- {drb-2.3.3 → drb-2.3.5}/drb/topics/resolver.py +6 -0
- {drb-2.3.3 → drb-2.3.5/drb.egg-info}/PKG-INFO +1 -1
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/SOURCES.txt +5 -0
- drb-2.3.5/tests/test_children_unresolved.py +62 -0
- drb-2.3.5/tests/test_manager_get_dao.py +27 -0
- drb-2.3.5/tests/test_node_context.py +42 -0
- drb-2.3.5/tests/test_topic_descriptor_discovery.py +55 -0
- {drb-2.3.3 → drb-2.3.5}/LICENCE.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/MANIFEST.in +0 -0
- {drb-2.3.3 → drb-2.3.5}/README.md +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/addons/addon.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/cortex_validator.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/events.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/factory.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/impls.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/item.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/path.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/predicate.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/core/signature.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/drivers/file/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/drivers/file/file.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/drivers/xml/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/drivers/xml/factory.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/drivers/xml/node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/exceptions/core.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/exceptions/file.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/keyring/bitwarden/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/keyring/bitwarden/bitwarden.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/nodes/logical_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/nodes/mutable_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/nodes/url_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/signatures/core.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/signatures/xquery.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/rdf_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/topic_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/topic_schema.yml +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/xml_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/dao/yaml_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/file/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/file/cortex.yml +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/topic.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/xml/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/topics/xml/cortex.yml +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/utils/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/utils/drb_python_script.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/utils/plugins.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/utils/url_security.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/utils/utils.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/XQueryLexer.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/XQueryParser.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/XQueryParserListener.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/XQueryParserVisitor.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/__init__.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_cmd.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_context.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_func.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_item.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_res_to_string.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_utils.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_variable.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/drb_xquery_visitor.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb/xquery/exceptions.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/dependency_links.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/entry_points.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/not-zip-safe +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/requires.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/drb.egg-info/top_level.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/pyproject.toml +0 -0
- {drb-2.3.3 → drb-2.3.5}/requirements.txt +0 -0
- {drb-2.3.3 → drb-2.3.5}/setup.cfg +0 -0
- {drb-2.3.3 → drb-2.3.5}/setup.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_abstract_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_addon.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_drb_node_list.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_drb_python_script.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_event.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_factory.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_factory_resolver.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_implementation_manager.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_keyring_bitwarden.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_logical_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_manager_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_node_descendant.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_path.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_rdf_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_rdf_dao_multi_url.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_signatures.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_topic.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_url_node.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_url_security.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_xml_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/tests/test_yaml_dao.py +0 -0
- {drb-2.3.3 → drb-2.3.5}/versioneer.py +0 -0
|
@@ -8,11 +8,11 @@ import json
|
|
|
8
8
|
|
|
9
9
|
version_json = '''
|
|
10
10
|
{
|
|
11
|
-
"date": "2026-06-
|
|
11
|
+
"date": "2026-06-22T12:26:43+0000",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.3.
|
|
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
|
|
@@ -61,6 +61,29 @@ class AbstractNode(DrbNode, abc.ABC):
|
|
|
61
61
|
return DrbNodeList(children)
|
|
62
62
|
raise TypeError(f"{type(item)} type not supported.")
|
|
63
63
|
|
|
64
|
+
@property
|
|
65
|
+
def children_unresolved(self) -> List[DrbNode]:
|
|
66
|
+
"""Direct children without topic resolution of each child.
|
|
67
|
+
|
|
68
|
+
``children`` (and bracket browsing) resolve every child to its
|
|
69
|
+
topic-specific node, so a recursive walk descends into the *content*
|
|
70
|
+
of each file (e.g. the XML element tree of a metadata file inside an
|
|
71
|
+
archive), which can dwarf the container's own structure. This
|
|
72
|
+
accessor returns the children as produced by the node itself, so a
|
|
73
|
+
structural traversal stays within the container (TICKET-003):
|
|
74
|
+
|
|
75
|
+
def walk(n):
|
|
76
|
+
return 1 + sum(walk(c) for c in n.children_unresolved)
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
list: the unresolved direct children.
|
|
80
|
+
"""
|
|
81
|
+
from drb.topics.resolver import DrbNodeList
|
|
82
|
+
children = self._browse_children()
|
|
83
|
+
if isinstance(children, DrbNodeList):
|
|
84
|
+
return children.unresolved
|
|
85
|
+
return list(children)
|
|
86
|
+
|
|
64
87
|
def descendant(self, path: str) -> DrbNode:
|
|
65
88
|
"""Navigate to a descendant node by a relative path.
|
|
66
89
|
|
|
@@ -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.
|
|
@@ -301,6 +301,12 @@ class DrbNodeList(list):
|
|
|
301
301
|
super(DrbNodeList, self).__init__()
|
|
302
302
|
self._list: List[DrbNode] = children
|
|
303
303
|
|
|
304
|
+
@property
|
|
305
|
+
def unresolved(self) -> List[DrbNode]:
|
|
306
|
+
"""The backing children as produced by the node, without resolving
|
|
307
|
+
each one to its topic-specific type."""
|
|
308
|
+
return list(self._list)
|
|
309
|
+
|
|
304
310
|
@staticmethod
|
|
305
311
|
def __resolve_node(node: DrbNode):
|
|
306
312
|
try:
|
|
@@ -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
|
|
@@ -75,6 +76,7 @@ drb/xquery/drb_xquery_visitor.py
|
|
|
75
76
|
drb/xquery/exceptions.py
|
|
76
77
|
tests/test_abstract_node.py
|
|
77
78
|
tests/test_addon.py
|
|
79
|
+
tests/test_children_unresolved.py
|
|
78
80
|
tests/test_drb_node_list.py
|
|
79
81
|
tests/test_drb_python_script.py
|
|
80
82
|
tests/test_event.py
|
|
@@ -84,12 +86,15 @@ tests/test_implementation_manager.py
|
|
|
84
86
|
tests/test_keyring_bitwarden.py
|
|
85
87
|
tests/test_logical_node.py
|
|
86
88
|
tests/test_manager_dao.py
|
|
89
|
+
tests/test_manager_get_dao.py
|
|
90
|
+
tests/test_node_context.py
|
|
87
91
|
tests/test_node_descendant.py
|
|
88
92
|
tests/test_path.py
|
|
89
93
|
tests/test_rdf_dao.py
|
|
90
94
|
tests/test_rdf_dao_multi_url.py
|
|
91
95
|
tests/test_signatures.py
|
|
92
96
|
tests/test_topic.py
|
|
97
|
+
tests/test_topic_descriptor_discovery.py
|
|
93
98
|
tests/test_url_node.py
|
|
94
99
|
tests/test_url_security.py
|
|
95
100
|
tests/test_xml_dao.py
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from drb.nodes.abstract_node import AbstractNode
|
|
4
|
+
from drb.nodes.logical_node import DrbLogicalNode
|
|
5
|
+
from drb.topics.resolver import DrbNodeList
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class _StubContainer(AbstractNode):
|
|
9
|
+
"""Node whose children are wrapped in a DrbNodeList, like a driver
|
|
10
|
+
using @resolve_children."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, name, raw_children):
|
|
13
|
+
super().__init__()
|
|
14
|
+
self.name = name
|
|
15
|
+
self._raw = raw_children
|
|
16
|
+
|
|
17
|
+
@property
|
|
18
|
+
def children(self):
|
|
19
|
+
return DrbNodeList(self._raw)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class TestChildrenUnresolved(unittest.TestCase):
|
|
23
|
+
"""Structural (non-resolving) child access (TICKET-003)."""
|
|
24
|
+
|
|
25
|
+
def test_node_list_unresolved_returns_backing(self):
|
|
26
|
+
a, b = DrbLogicalNode('a'), DrbLogicalNode('b')
|
|
27
|
+
nl = DrbNodeList([a, b])
|
|
28
|
+
self.assertEqual([a, b], nl.unresolved)
|
|
29
|
+
# The backing objects are returned as-is (no resolution attempted).
|
|
30
|
+
self.assertIs(a, nl.unresolved[0])
|
|
31
|
+
|
|
32
|
+
def test_children_unresolved_bypasses_resolution(self):
|
|
33
|
+
a, b = DrbLogicalNode('a.xml'), DrbLogicalNode('b.zip')
|
|
34
|
+
stub = _StubContainer('c', [a, b])
|
|
35
|
+
unresolved = stub.children_unresolved
|
|
36
|
+
self.assertEqual(['a.xml', 'b.zip'], [n.name for n in unresolved])
|
|
37
|
+
# Same raw objects as provided, untouched by the resolver.
|
|
38
|
+
self.assertIs(a, unresolved[0])
|
|
39
|
+
self.assertIs(b, unresolved[1])
|
|
40
|
+
|
|
41
|
+
def test_children_unresolved_on_plain_list_node(self):
|
|
42
|
+
root = DrbLogicalNode('root')
|
|
43
|
+
root.append_child(DrbLogicalNode('child'))
|
|
44
|
+
self.assertEqual(['child'],
|
|
45
|
+
[n.name for n in root.children_unresolved])
|
|
46
|
+
|
|
47
|
+
def test_structural_walk_is_bounded(self):
|
|
48
|
+
# A small tree; walking via children_unresolved counts every node
|
|
49
|
+
# exactly once without descending into any resolved content.
|
|
50
|
+
root = DrbLogicalNode('root')
|
|
51
|
+
sub = DrbLogicalNode('sub')
|
|
52
|
+
sub.append_child(DrbLogicalNode('leaf'))
|
|
53
|
+
root.append_child(sub)
|
|
54
|
+
|
|
55
|
+
def walk(n):
|
|
56
|
+
return 1 + sum(walk(c) for c in n.children_unresolved)
|
|
57
|
+
|
|
58
|
+
self.assertEqual(3, walk(root))
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
if __name__ == '__main__':
|
|
62
|
+
unittest.main()
|
|
@@ -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
|
{drb-2.3.3 → drb-2.3.5}/setup.py
RENAMED
|
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
|