drb 2.4.3__tar.gz → 2.4.4__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.4.3/drb.egg-info → drb-2.4.4}/PKG-INFO +1 -1
- {drb-2.4.3 → drb-2.4.4}/drb/core/_version.py +3 -3
- {drb-2.4.3 → drb-2.4.4}/drb/signatures/core.py +42 -5
- {drb-2.4.3 → drb-2.4.4}/drb/topics/resolver.py +54 -32
- {drb-2.4.3 → drb-2.4.4/drb.egg-info}/PKG-INFO +1 -1
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/SOURCES.txt +3 -0
- drb-2.4.4/tests/test_finest_multiparent.py +71 -0
- drb-2.4.4/tests/test_resolver_recursion_guard.py +65 -0
- drb-2.4.4/tests/test_signature_inline_flags.py +18 -0
- {drb-2.4.3 → drb-2.4.4}/LICENCE.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/MANIFEST.in +0 -0
- {drb-2.4.3 → drb-2.4.4}/README.md +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/addons/addon.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/context.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/cortex_validator.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/events.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/factory.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/impls.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/item.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/path.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/predicate.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/core/signature.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/file/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/file/cortex.ttl +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/file/file.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/xml/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/xml/cortex.ttl +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/xml/factory.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/drivers/xml/node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/exceptions/core.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/exceptions/file.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/keyring/bitwarden/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/keyring/bitwarden/bitwarden.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/nodes/abstract_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/nodes/logical_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/nodes/mutable_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/nodes/url_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/signatures/hierarchy.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/signatures/xquery.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/manager_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/rdf_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/topic_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/topic_schema.yml +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/dao/xml_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/file/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/file/cortex.ttl +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/topic.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/xml/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/topics/xml/cortex.ttl +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/utils/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/utils/drb_python_script.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/utils/plugins.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/utils/url_security.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/utils/utils.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/XQueryLexer.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/XQueryParser.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/XQueryParserListener.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/XQueryParserVisitor.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/__init__.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_cmd.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_context.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_func.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_item.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_res_to_string.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_utils.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_variable.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/drb_xquery_visitor.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb/xquery/exceptions.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/dependency_links.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/entry_points.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/not-zip-safe +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/requires.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/drb.egg-info/top_level.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/pyproject.toml +0 -0
- {drb-2.4.3 → drb-2.4.4}/requirements.txt +0 -0
- {drb-2.4.3 → drb-2.4.4}/setup.cfg +0 -0
- {drb-2.4.3 → drb-2.4.4}/setup.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_abstract_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_addon.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_children_unresolved.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_core_topic_ttl.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_cortex_validator.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_drb_node_list.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_drb_python_script.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_event.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_factory.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_factory_resolver.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_implementation_coupling.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_implementation_manager.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_keyring_bitwarden.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_logical_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_manager_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_manager_get_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_node_context.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_node_descendant.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_path.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_protocol_dispatch.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_rdf_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_rdf_dao_multi_url.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_rdf_dao_scheme.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_rdf_dao_signatures.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_scheme_force_impl.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_scheme_force_url.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_signature_exact.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_signature_hierarchy.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_signatures.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_topic.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_topic_descriptor_discovery.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_url_node.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_url_security.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/tests/test_xml_dao.py +0 -0
- {drb-2.4.3 → drb-2.4.4}/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-30T02:14:50+0000",
|
|
12
12
|
"dirty": false,
|
|
13
13
|
"error": null,
|
|
14
|
-
"full-revisionid": "
|
|
15
|
-
"version": "2.4.
|
|
14
|
+
"full-revisionid": "6de9fd1d1e819008ecdd4ddbd56a71bd2e99c4ab",
|
|
15
|
+
"version": "2.4.4"
|
|
16
16
|
}
|
|
17
17
|
''' # END VERSION_JSON
|
|
18
18
|
|
|
@@ -1,10 +1,44 @@
|
|
|
1
|
+
import re
|
|
2
|
+
import logging
|
|
3
|
+
|
|
1
4
|
from drb.core import DrbNode
|
|
2
5
|
from drb.core.predicate import Predicate
|
|
3
6
|
from drb.utils.drb_python_script import exec_with_return
|
|
4
7
|
from drb.exceptions.core import DrbException
|
|
5
8
|
from drb.core.signature import Signature, SignatureAggregator
|
|
6
|
-
|
|
7
|
-
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
_INLINE_FLAG_GROUP = re.compile(r'\(\?([aiLmsux]+)\)')
|
|
12
|
+
_FLAG_CHARS = {'a': re.A, 'i': re.I, 'L': re.L, 'm': re.M,
|
|
13
|
+
's': re.S, 'u': re.U, 'x': re.X}
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _compile_regex(pattern: str):
|
|
17
|
+
"""Compile a regex, tolerating global inline flags (e.g. ``(?i)``)
|
|
18
|
+
placed anywhere in the pattern. Python 3.11+ rejects a global inline
|
|
19
|
+
flag that is not at position 0, but drb-java / legacy descriptors
|
|
20
|
+
author them after an anchor (``^(?i)...``). A bare ``(?i)`` group is
|
|
21
|
+
already global, so its flags are moved to the compile-time ``flags``
|
|
22
|
+
argument and the group is stripped from the pattern. Scoped groups
|
|
23
|
+
like ``(?i:...)`` (with a colon) are untouched.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
pattern: The raw regex pattern string, possibly containing
|
|
27
|
+
global inline flag groups.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
A compiled :class:`re.Pattern` with any extracted flags applied.
|
|
31
|
+
"""
|
|
32
|
+
chars = set()
|
|
33
|
+
for m in _INLINE_FLAG_GROUP.finditer(pattern):
|
|
34
|
+
chars.update(m.group(1))
|
|
35
|
+
if not chars:
|
|
36
|
+
return re.compile(pattern)
|
|
37
|
+
cleaned = _INLINE_FLAG_GROUP.sub('', pattern)
|
|
38
|
+
flags = 0
|
|
39
|
+
for ch in chars:
|
|
40
|
+
flags |= _FLAG_CHARS[ch]
|
|
41
|
+
return re.compile(cleaned, flags)
|
|
8
42
|
|
|
9
43
|
|
|
10
44
|
class NameSignature(Signature):
|
|
@@ -16,9 +50,10 @@ class NameSignature(Signature):
|
|
|
16
50
|
|
|
17
51
|
def __init__(self, regex: str):
|
|
18
52
|
self.__regex = regex
|
|
53
|
+
self.__pattern = _compile_regex(regex)
|
|
19
54
|
|
|
20
55
|
def matches(self, node: DrbNode) -> bool:
|
|
21
|
-
return
|
|
56
|
+
return self.__pattern.match(node.name) is not None
|
|
22
57
|
|
|
23
58
|
def to_dict(self) -> dict:
|
|
24
59
|
return {self.get_name(): self.__regex}
|
|
@@ -37,9 +72,10 @@ class NamespaceSignature(Signature):
|
|
|
37
72
|
|
|
38
73
|
def __init__(self, regex: str):
|
|
39
74
|
self.__regex = regex
|
|
75
|
+
self.__pattern = _compile_regex(regex)
|
|
40
76
|
|
|
41
77
|
def matches(self, node: DrbNode) -> bool:
|
|
42
|
-
return
|
|
78
|
+
return self.__pattern.match(node.namespace_uri) is not None
|
|
43
79
|
|
|
44
80
|
def to_dict(self) -> dict:
|
|
45
81
|
return {self.get_name(): self.__regex}
|
|
@@ -92,9 +128,10 @@ class PathSignature(Signature):
|
|
|
92
128
|
|
|
93
129
|
def __init__(self, regex: str):
|
|
94
130
|
self.__regex = regex
|
|
131
|
+
self.__pattern = _compile_regex(regex)
|
|
95
132
|
|
|
96
133
|
def matches(self, node: DrbNode) -> bool:
|
|
97
|
-
return
|
|
134
|
+
return self.__pattern.match(node.path.name) is not None
|
|
98
135
|
|
|
99
136
|
def to_dict(self) -> dict:
|
|
100
137
|
return {self.get_name(): self.__regex}
|
|
@@ -4,6 +4,7 @@ import logging
|
|
|
4
4
|
import pathlib
|
|
5
5
|
import sys
|
|
6
6
|
import re
|
|
7
|
+
import threading
|
|
7
8
|
|
|
8
9
|
from urllib.parse import urlparse
|
|
9
10
|
from typing import List, Optional, Tuple, Union
|
|
@@ -19,6 +20,8 @@ from drb.addons.addon import AddonManager
|
|
|
19
20
|
|
|
20
21
|
logger = logging.getLogger('DrbResolver')
|
|
21
22
|
|
|
23
|
+
_resolution_guard = threading.local()
|
|
24
|
+
|
|
22
25
|
|
|
23
26
|
def _is_remote_url(parsed_path):
|
|
24
27
|
"""
|
|
@@ -227,7 +230,7 @@ class _DrbFactoryResolver(DrbFactory):
|
|
|
227
230
|
DrbTopic: the finest topic matching the given node
|
|
228
231
|
"""
|
|
229
232
|
topics = [x for x in ManagerDao().get_all_drb_topics()
|
|
230
|
-
if x.subClassOf is not None if
|
|
233
|
+
if x.subClassOf is not None if finest.id in x.subClassOf]
|
|
231
234
|
for topic in topics:
|
|
232
235
|
node = forced_factory(topic, node)
|
|
233
236
|
if topic.matches(node):
|
|
@@ -356,38 +359,57 @@ class _DrbFactoryResolver(DrbFactory):
|
|
|
356
359
|
node = UrlNode(source)
|
|
357
360
|
else:
|
|
358
361
|
node = source
|
|
359
|
-
|
|
360
|
-
if
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
362
|
+
active = getattr(_resolution_guard, 'active', None)
|
|
363
|
+
if active is None:
|
|
364
|
+
active = set()
|
|
365
|
+
_resolution_guard.active = active
|
|
366
|
+
try:
|
|
367
|
+
key = node.path.path
|
|
368
|
+
except Exception: # noqa: BLE001
|
|
369
|
+
key = None
|
|
370
|
+
if key is not None and key in active:
|
|
371
|
+
raise DrbFactoryException(
|
|
372
|
+
f'Cyclic resolution detected for node path: {key}')
|
|
373
|
+
if key is not None:
|
|
374
|
+
active.add(key)
|
|
375
|
+
try:
|
|
376
|
+
protocol = None
|
|
377
|
+
if node.parent is None:
|
|
378
|
+
dispatched = self.__dispatch_scheme(node)
|
|
379
|
+
if dispatched is not None:
|
|
380
|
+
protocol, node = dispatched
|
|
381
|
+
else:
|
|
382
|
+
protocol = self.__retrieve_protocol(node)
|
|
383
|
+
if protocol is None:
|
|
384
|
+
raise DrbFactoryException(
|
|
385
|
+
f'Cannot resolve: {source}')
|
|
386
|
+
node = _create_via_factory(protocol, node)
|
|
387
|
+
|
|
388
|
+
container, node = self.__retrieve_container(node)
|
|
389
|
+
if container is not None and container.factory is not None:
|
|
390
|
+
node = _create_via_factory(container, node)
|
|
391
|
+
|
|
392
|
+
formatting = self.__retrieve_formatting(node)
|
|
393
|
+
if formatting is not None:
|
|
394
|
+
if formatting.factory is not None:
|
|
395
|
+
node = _create_via_factory(formatting, node)
|
|
396
|
+
t, n = self.__finest_drb_topic(node, formatting)
|
|
397
|
+
elif container is not None:
|
|
398
|
+
t, n = container, node
|
|
399
|
+
elif protocol is not None:
|
|
400
|
+
t, n = protocol, node
|
|
364
401
|
else:
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
if formatting.factory is not None:
|
|
377
|
-
node = _create_via_factory(formatting, node)
|
|
378
|
-
t, n = self.__finest_drb_topic(node, formatting)
|
|
379
|
-
elif container is not None:
|
|
380
|
-
t, n = container, node
|
|
381
|
-
elif protocol is not None:
|
|
382
|
-
t, n = protocol, node
|
|
383
|
-
else:
|
|
384
|
-
raise DrbFactoryException(f'Cannot resolve: {source}')
|
|
385
|
-
|
|
386
|
-
addons = filter(lambda x: x.can_apply(t),
|
|
387
|
-
AddonManager().get_all_addons())
|
|
388
|
-
for addon in addons:
|
|
389
|
-
node.add_impl(addon.return_type(), addon.apply, addon.identifier())
|
|
390
|
-
return t, n
|
|
402
|
+
raise DrbFactoryException(f'Cannot resolve: {source}')
|
|
403
|
+
|
|
404
|
+
addons = filter(lambda x: x.can_apply(t),
|
|
405
|
+
AddonManager().get_all_addons())
|
|
406
|
+
for addon in addons:
|
|
407
|
+
node.add_impl(
|
|
408
|
+
addon.return_type(), addon.apply, addon.identifier())
|
|
409
|
+
return t, n
|
|
410
|
+
finally:
|
|
411
|
+
if key is not None:
|
|
412
|
+
active.discard(key)
|
|
391
413
|
|
|
392
414
|
def resolve(self, source: Union[str, DrbNode]) \
|
|
393
415
|
-> Tuple[DrbTopic, Optional[DrbNode]]:
|
|
@@ -86,6 +86,7 @@ tests/test_drb_python_script.py
|
|
|
86
86
|
tests/test_event.py
|
|
87
87
|
tests/test_factory.py
|
|
88
88
|
tests/test_factory_resolver.py
|
|
89
|
+
tests/test_finest_multiparent.py
|
|
89
90
|
tests/test_implementation_coupling.py
|
|
90
91
|
tests/test_implementation_manager.py
|
|
91
92
|
tests/test_keyring_bitwarden.py
|
|
@@ -100,10 +101,12 @@ tests/test_rdf_dao.py
|
|
|
100
101
|
tests/test_rdf_dao_multi_url.py
|
|
101
102
|
tests/test_rdf_dao_scheme.py
|
|
102
103
|
tests/test_rdf_dao_signatures.py
|
|
104
|
+
tests/test_resolver_recursion_guard.py
|
|
103
105
|
tests/test_scheme_force_impl.py
|
|
104
106
|
tests/test_scheme_force_url.py
|
|
105
107
|
tests/test_signature_exact.py
|
|
106
108
|
tests/test_signature_hierarchy.py
|
|
109
|
+
tests/test_signature_inline_flags.py
|
|
107
110
|
tests/test_signatures.py
|
|
108
111
|
tests/test_topic.py
|
|
109
112
|
tests/test_topic_descriptor_discovery.py
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
import unittest
|
|
4
|
+
import uuid
|
|
5
|
+
|
|
6
|
+
from drb.nodes.logical_node import DrbLogicalNode
|
|
7
|
+
from drb.topics.dao import ManagerDao
|
|
8
|
+
from drb.topics.dao.rdf_dao import RDFDao
|
|
9
|
+
import drb.topics.resolver as resolver
|
|
10
|
+
|
|
11
|
+
_IDS = ("a1a1a1a1-0000-0000-0000-00000000000a",
|
|
12
|
+
"b2b2b2b2-0000-0000-0000-00000000000b",
|
|
13
|
+
"c3c3c3c3-0000-0000-0000-00000000000c")
|
|
14
|
+
|
|
15
|
+
_TTL = """\
|
|
16
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
17
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
18
|
+
@prefix drb: <http://www.gael.fr/drb#> .
|
|
19
|
+
@prefix t: <http://example.org/mp/> .
|
|
20
|
+
|
|
21
|
+
t:base_a a owl:Class ; rdfs:label "mp_base_a" ;
|
|
22
|
+
drb:id "a1a1a1a1-0000-0000-0000-00000000000a" ;
|
|
23
|
+
drb:category "CONTAINER" ;
|
|
24
|
+
rdfs:subClassOf <http://www.gael.fr/drb#item> ;
|
|
25
|
+
drb:signature [ drb:nameMatch "mpnode" ] .
|
|
26
|
+
t:base_b a owl:Class ; rdfs:label "mp_base_b" ;
|
|
27
|
+
drb:id "b2b2b2b2-0000-0000-0000-00000000000b" ;
|
|
28
|
+
drb:category "CONTAINER" ;
|
|
29
|
+
rdfs:subClassOf <http://www.gael.fr/drb#item> ;
|
|
30
|
+
drb:signature [ drb:nameMatch "mpnode" ] .
|
|
31
|
+
t:child a owl:Class ; rdfs:label "mp_child" ;
|
|
32
|
+
drb:id "c3c3c3c3-0000-0000-0000-00000000000c" ;
|
|
33
|
+
drb:category "CONTAINER" ;
|
|
34
|
+
rdfs:subClassOf t:base_a, t:base_b ;
|
|
35
|
+
drb:signature [ drb:nameMatch "mpnode" ] .
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TestFinestMultiParent(unittest.TestCase):
|
|
40
|
+
def setUp(self):
|
|
41
|
+
fd, self._ttl = tempfile.mkstemp(suffix=".ttl")
|
|
42
|
+
with os.fdopen(fd, "w") as f:
|
|
43
|
+
f.write(_TTL)
|
|
44
|
+
ManagerDao().add_dao_instance(RDFDao(self._ttl))
|
|
45
|
+
self.addCleanup(self._clean)
|
|
46
|
+
|
|
47
|
+
def _clean(self):
|
|
48
|
+
for u in _IDS:
|
|
49
|
+
try:
|
|
50
|
+
ManagerDao().delete(uuid.UUID(u))
|
|
51
|
+
except Exception:
|
|
52
|
+
pass
|
|
53
|
+
try:
|
|
54
|
+
os.unlink(self._ttl)
|
|
55
|
+
except OSError:
|
|
56
|
+
pass
|
|
57
|
+
|
|
58
|
+
def test_descends_via_non_first_parent(self):
|
|
59
|
+
topics = ManagerDao().get_all_drb_topics()
|
|
60
|
+
child = [t for t in topics
|
|
61
|
+
if t.uri and t.uri.endswith('/mp/child')][0]
|
|
62
|
+
# child has two parents; pick one that is NOT subClassOf[0]
|
|
63
|
+
self.assertEqual(2, len(child.subClassOf))
|
|
64
|
+
non_first = child.subClassOf[1]
|
|
65
|
+
parent = [t for t in topics if t.id == non_first][0]
|
|
66
|
+
res = resolver._DrbFactoryResolver()
|
|
67
|
+
node = DrbLogicalNode("mpnode")
|
|
68
|
+
topic, _ = res._DrbFactoryResolver__finest_drb_topic(node, parent)
|
|
69
|
+
self.assertTrue(
|
|
70
|
+
str(topic.uri).endswith('/mp/child'),
|
|
71
|
+
f"descent stopped at {topic.uri}, expected .../mp/child")
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import tempfile
|
|
3
|
+
import unittest
|
|
4
|
+
|
|
5
|
+
import drb.topics.resolver as resolver
|
|
6
|
+
from drb.nodes.logical_node import DrbLogicalNode
|
|
7
|
+
from drb.topics.dao import ManagerDao
|
|
8
|
+
from drb.topics.dao.rdf_dao import RDFDao
|
|
9
|
+
from drb.topics.resolver import DrbNodeList
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
# A node whose resolved children list contains itself -> a resolution cycle.
|
|
13
|
+
class _CyclicNode(DrbLogicalNode):
|
|
14
|
+
@property
|
|
15
|
+
def children(self):
|
|
16
|
+
return DrbNodeList([self])
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
_LOOP_TTL = """\
|
|
20
|
+
@prefix owl: <http://www.w3.org/2002/07/owl#> .
|
|
21
|
+
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
|
|
22
|
+
@prefix drb: <http://www.gael.fr/drb#> .
|
|
23
|
+
@prefix t: <http://example.org/test/> .
|
|
24
|
+
|
|
25
|
+
t:loop a owl:Class ;
|
|
26
|
+
rdfs:label "loop" ;
|
|
27
|
+
drb:id "aaaaaaaa-0000-0000-0000-000000000001" ;
|
|
28
|
+
drb:category "CONTAINER" ;
|
|
29
|
+
rdfs:subClassOf <http://www.gael.fr/drb#item> ;
|
|
30
|
+
drb:signature [ drb:nameMatch "loop" ;
|
|
31
|
+
drb:xqueryTest "*[fn:matches(fn:name(),'loop')]" ] .
|
|
32
|
+
"""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class TestResolverRecursionGuard(unittest.TestCase):
|
|
36
|
+
def setUp(self):
|
|
37
|
+
fd, self._ttl = tempfile.mkstemp(suffix=".ttl")
|
|
38
|
+
with os.fdopen(fd, "w") as f:
|
|
39
|
+
f.write(_LOOP_TTL)
|
|
40
|
+
self._dao = ManagerDao().add_dao_instance(RDFDao(self._ttl))
|
|
41
|
+
self.addCleanup(self._cleanup)
|
|
42
|
+
|
|
43
|
+
def _cleanup(self):
|
|
44
|
+
try:
|
|
45
|
+
import uuid
|
|
46
|
+
ManagerDao().delete(
|
|
47
|
+
uuid.UUID("aaaaaaaa-0000-0000-0000-000000000001"))
|
|
48
|
+
except Exception:
|
|
49
|
+
pass
|
|
50
|
+
try:
|
|
51
|
+
os.unlink(self._ttl)
|
|
52
|
+
except OSError:
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
def test_cyclic_resolution_terminates(self):
|
|
56
|
+
# Without the guard this recurses without bound (RecursionError, then
|
|
57
|
+
# swallowed -> DrbFactoryException); with the guard it terminates and
|
|
58
|
+
# classifies the node as the 'loop' container.
|
|
59
|
+
# The node must have a parent so the resolver skips the protocol/root
|
|
60
|
+
# dispatch path and goes directly to container signature matching,
|
|
61
|
+
# where the xquery '*' iterates children via DrbNodeList -> create().
|
|
62
|
+
parent = DrbLogicalNode("root")
|
|
63
|
+
node = _CyclicNode("loop", parent=parent)
|
|
64
|
+
topic, _ = resolver.resolve(node)
|
|
65
|
+
self.assertEqual("loop", topic.label)
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import unittest
|
|
2
|
+
|
|
3
|
+
from drb.nodes.logical_node import DrbLogicalNode
|
|
4
|
+
from drb.signatures.core import NameSignature
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class TestNameSignatureInlineFlags(unittest.TestCase):
|
|
8
|
+
def test_misplaced_inline_flag_compiles_and_matches(self):
|
|
9
|
+
# (?i) after the ^ anchor: invalid as a raw py3.11 regex.
|
|
10
|
+
sig = NameSignature(r'^(?i)S2[AB]_.*\.SAFE$')
|
|
11
|
+
self.assertTrue(sig.matches(DrbLogicalNode('S2B_x.SAFE')))
|
|
12
|
+
# global case-insensitivity preserved
|
|
13
|
+
self.assertTrue(sig.matches(DrbLogicalNode('s2b_x.safe')))
|
|
14
|
+
self.assertFalse(sig.matches(DrbLogicalNode('X9_x.SAFE')))
|
|
15
|
+
|
|
16
|
+
def test_to_dict_keeps_the_original_pattern(self):
|
|
17
|
+
pat = r'^(?i)S2[AB]_.*\.SAFE$'
|
|
18
|
+
self.assertEqual({'name': pat}, NameSignature(pat).to_dict())
|
|
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
|
{drb-2.4.3 → drb-2.4.4}/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
|
|
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
|