drb 2.6.2__tar.gz → 2.7.0__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 (125) hide show
  1. {drb-2.6.2/drb.egg-info → drb-2.7.0}/PKG-INFO +1 -1
  2. {drb-2.6.2 → drb-2.7.0}/drb/core/_version.py +3 -3
  3. drb-2.7.0/drb/utils/io.py +206 -0
  4. {drb-2.6.2 → drb-2.7.0/drb.egg-info}/PKG-INFO +1 -1
  5. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/SOURCES.txt +1 -0
  6. {drb-2.6.2 → drb-2.7.0}/LICENCE.txt +0 -0
  7. {drb-2.6.2 → drb-2.7.0}/MANIFEST.in +0 -0
  8. {drb-2.6.2 → drb-2.7.0}/README.md +0 -0
  9. {drb-2.6.2 → drb-2.7.0}/drb/addons/addon.py +0 -0
  10. {drb-2.6.2 → drb-2.7.0}/drb/core/__init__.py +0 -0
  11. {drb-2.6.2 → drb-2.7.0}/drb/core/auth.py +0 -0
  12. {drb-2.6.2 → drb-2.7.0}/drb/core/context.py +0 -0
  13. {drb-2.6.2 → drb-2.7.0}/drb/core/cortex_validator.py +0 -0
  14. {drb-2.6.2 → drb-2.7.0}/drb/core/events.py +0 -0
  15. {drb-2.6.2 → drb-2.7.0}/drb/core/factory.py +0 -0
  16. {drb-2.6.2 → drb-2.7.0}/drb/core/impls.py +0 -0
  17. {drb-2.6.2 → drb-2.7.0}/drb/core/item.py +0 -0
  18. {drb-2.6.2 → drb-2.7.0}/drb/core/node.py +0 -0
  19. {drb-2.6.2 → drb-2.7.0}/drb/core/path.py +0 -0
  20. {drb-2.6.2 → drb-2.7.0}/drb/core/predicate.py +0 -0
  21. {drb-2.6.2 → drb-2.7.0}/drb/core/signature.py +0 -0
  22. {drb-2.6.2 → drb-2.7.0}/drb/drivers/file/__init__.py +0 -0
  23. {drb-2.6.2 → drb-2.7.0}/drb/drivers/file/cortex.ttl +0 -0
  24. {drb-2.6.2 → drb-2.7.0}/drb/drivers/file/file.py +0 -0
  25. {drb-2.6.2 → drb-2.7.0}/drb/drivers/xml/__init__.py +0 -0
  26. {drb-2.6.2 → drb-2.7.0}/drb/drivers/xml/cortex.ttl +0 -0
  27. {drb-2.6.2 → drb-2.7.0}/drb/drivers/xml/factory.py +0 -0
  28. {drb-2.6.2 → drb-2.7.0}/drb/drivers/xml/node.py +0 -0
  29. {drb-2.6.2 → drb-2.7.0}/drb/exceptions/core.py +0 -0
  30. {drb-2.6.2 → drb-2.7.0}/drb/exceptions/file.py +0 -0
  31. {drb-2.6.2 → drb-2.7.0}/drb/keyring/bitwarden/__init__.py +0 -0
  32. {drb-2.6.2 → drb-2.7.0}/drb/keyring/bitwarden/bitwarden.py +0 -0
  33. {drb-2.6.2 → drb-2.7.0}/drb/nodes/abstract_node.py +0 -0
  34. {drb-2.6.2 → drb-2.7.0}/drb/nodes/logical_node.py +0 -0
  35. {drb-2.6.2 → drb-2.7.0}/drb/nodes/mutable_node.py +0 -0
  36. {drb-2.6.2 → drb-2.7.0}/drb/nodes/url_node.py +0 -0
  37. {drb-2.6.2 → drb-2.7.0}/drb/signatures/core.py +0 -0
  38. {drb-2.6.2 → drb-2.7.0}/drb/signatures/hierarchy.py +0 -0
  39. {drb-2.6.2 → drb-2.7.0}/drb/signatures/xquery.py +0 -0
  40. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/__init__.py +0 -0
  41. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/manager_dao.py +0 -0
  42. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/rdf_dao.py +0 -0
  43. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/topic_dao.py +0 -0
  44. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/topic_schema.yml +0 -0
  45. {drb-2.6.2 → drb-2.7.0}/drb/topics/dao/xml_dao.py +0 -0
  46. {drb-2.6.2 → drb-2.7.0}/drb/topics/file/__init__.py +0 -0
  47. {drb-2.6.2 → drb-2.7.0}/drb/topics/file/cortex.ttl +0 -0
  48. {drb-2.6.2 → drb-2.7.0}/drb/topics/resolver.py +0 -0
  49. {drb-2.6.2 → drb-2.7.0}/drb/topics/topic.py +0 -0
  50. {drb-2.6.2 → drb-2.7.0}/drb/topics/xml/__init__.py +0 -0
  51. {drb-2.6.2 → drb-2.7.0}/drb/topics/xml/cortex.ttl +0 -0
  52. {drb-2.6.2 → drb-2.7.0}/drb/utils/__init__.py +0 -0
  53. {drb-2.6.2 → drb-2.7.0}/drb/utils/drb_python_script.py +0 -0
  54. {drb-2.6.2 → drb-2.7.0}/drb/utils/plugins.py +0 -0
  55. {drb-2.6.2 → drb-2.7.0}/drb/utils/url_security.py +0 -0
  56. {drb-2.6.2 → drb-2.7.0}/drb/utils/utils.py +0 -0
  57. {drb-2.6.2 → drb-2.7.0}/drb/xquery/XQueryLexer.py +0 -0
  58. {drb-2.6.2 → drb-2.7.0}/drb/xquery/XQueryParser.py +0 -0
  59. {drb-2.6.2 → drb-2.7.0}/drb/xquery/XQueryParserListener.py +0 -0
  60. {drb-2.6.2 → drb-2.7.0}/drb/xquery/XQueryParserVisitor.py +0 -0
  61. {drb-2.6.2 → drb-2.7.0}/drb/xquery/__init__.py +0 -0
  62. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery.py +0 -0
  63. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_cmd.py +0 -0
  64. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_context.py +0 -0
  65. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_func.py +0 -0
  66. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_item.py +0 -0
  67. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_res_to_string.py +0 -0
  68. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_utils.py +0 -0
  69. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_variable.py +0 -0
  70. {drb-2.6.2 → drb-2.7.0}/drb/xquery/drb_xquery_visitor.py +0 -0
  71. {drb-2.6.2 → drb-2.7.0}/drb/xquery/exceptions.py +0 -0
  72. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/dependency_links.txt +0 -0
  73. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/entry_points.txt +0 -0
  74. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/not-zip-safe +0 -0
  75. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/requires.txt +0 -0
  76. {drb-2.6.2 → drb-2.7.0}/drb.egg-info/top_level.txt +0 -0
  77. {drb-2.6.2 → drb-2.7.0}/pyproject.toml +0 -0
  78. {drb-2.6.2 → drb-2.7.0}/requirements.txt +0 -0
  79. {drb-2.6.2 → drb-2.7.0}/setup.cfg +0 -0
  80. {drb-2.6.2 → drb-2.7.0}/setup.py +0 -0
  81. {drb-2.6.2 → drb-2.7.0}/tests/test_abstract_node.py +0 -0
  82. {drb-2.6.2 → drb-2.7.0}/tests/test_addon.py +0 -0
  83. {drb-2.6.2 → drb-2.7.0}/tests/test_auth.py +0 -0
  84. {drb-2.6.2 → drb-2.7.0}/tests/test_children_unresolved.py +0 -0
  85. {drb-2.6.2 → drb-2.7.0}/tests/test_core_topic_ttl.py +0 -0
  86. {drb-2.6.2 → drb-2.7.0}/tests/test_cortex_validator.py +0 -0
  87. {drb-2.6.2 → drb-2.7.0}/tests/test_drb_node_list.py +0 -0
  88. {drb-2.6.2 → drb-2.7.0}/tests/test_drb_python_script.py +0 -0
  89. {drb-2.6.2 → drb-2.7.0}/tests/test_event.py +0 -0
  90. {drb-2.6.2 → drb-2.7.0}/tests/test_factory.py +0 -0
  91. {drb-2.6.2 → drb-2.7.0}/tests/test_factory_resolver.py +0 -0
  92. {drb-2.6.2 → drb-2.7.0}/tests/test_finest_multiparent.py +0 -0
  93. {drb-2.6.2 → drb-2.7.0}/tests/test_implementation_coupling.py +0 -0
  94. {drb-2.6.2 → drb-2.7.0}/tests/test_implementation_manager.py +0 -0
  95. {drb-2.6.2 → drb-2.7.0}/tests/test_keyring_bitwarden.py +0 -0
  96. {drb-2.6.2 → drb-2.7.0}/tests/test_logical_node.py +0 -0
  97. {drb-2.6.2 → drb-2.7.0}/tests/test_manager_dao.py +0 -0
  98. {drb-2.6.2 → drb-2.7.0}/tests/test_manager_get_dao.py +0 -0
  99. {drb-2.6.2 → drb-2.7.0}/tests/test_node_context.py +0 -0
  100. {drb-2.6.2 → drb-2.7.0}/tests/test_node_context_manager.py +0 -0
  101. {drb-2.6.2 → drb-2.7.0}/tests/test_node_descendant.py +0 -0
  102. {drb-2.6.2 → drb-2.7.0}/tests/test_path.py +0 -0
  103. {drb-2.6.2 → drb-2.7.0}/tests/test_protocol_dispatch.py +0 -0
  104. {drb-2.6.2 → drb-2.7.0}/tests/test_rdf_dao.py +0 -0
  105. {drb-2.6.2 → drb-2.7.0}/tests/test_rdf_dao_multi_url.py +0 -0
  106. {drb-2.6.2 → drb-2.7.0}/tests/test_rdf_dao_scheme.py +0 -0
  107. {drb-2.6.2 → drb-2.7.0}/tests/test_rdf_dao_signatures.py +0 -0
  108. {drb-2.6.2 → drb-2.7.0}/tests/test_resolver_auth.py +0 -0
  109. {drb-2.6.2 → drb-2.7.0}/tests/test_resolver_format_alias.py +0 -0
  110. {drb-2.6.2 → drb-2.7.0}/tests/test_resolver_implicit_file.py +0 -0
  111. {drb-2.6.2 → drb-2.7.0}/tests/test_resolver_recursion_guard.py +0 -0
  112. {drb-2.6.2 → drb-2.7.0}/tests/test_scheme_force_impl.py +0 -0
  113. {drb-2.6.2 → drb-2.7.0}/tests/test_scheme_force_url.py +0 -0
  114. {drb-2.6.2 → drb-2.7.0}/tests/test_signature_duplicate_warning.py +0 -0
  115. {drb-2.6.2 → drb-2.7.0}/tests/test_signature_exact.py +0 -0
  116. {drb-2.6.2 → drb-2.7.0}/tests/test_signature_hierarchy.py +0 -0
  117. {drb-2.6.2 → drb-2.7.0}/tests/test_signature_inline_flags.py +0 -0
  118. {drb-2.6.2 → drb-2.7.0}/tests/test_signatures.py +0 -0
  119. {drb-2.6.2 → drb-2.7.0}/tests/test_topic.py +0 -0
  120. {drb-2.6.2 → drb-2.7.0}/tests/test_topic_descriptor_discovery.py +0 -0
  121. {drb-2.6.2 → drb-2.7.0}/tests/test_url_node.py +0 -0
  122. {drb-2.6.2 → drb-2.7.0}/tests/test_url_security.py +0 -0
  123. {drb-2.6.2 → drb-2.7.0}/tests/test_xml_dao.py +0 -0
  124. {drb-2.6.2 → drb-2.7.0}/tests/test_xml_xquery_import_order.py +0 -0
  125. {drb-2.6.2 → drb-2.7.0}/versioneer.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drb
3
- Version: 2.6.2
3
+ Version: 2.7.0
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-07-04T01:16:50+0000",
11
+ "date": "2026-07-04T08:23:09+0000",
12
12
  "dirty": false,
13
13
  "error": null,
14
- "full-revisionid": "922738f837cc758574aea56aa913ef07bc4b45fa",
15
- "version": "2.6.2"
14
+ "full-revisionid": "41b7207a532b8d24d4a0edac7129dff08e02d789",
15
+ "version": "2.7.0"
16
16
  }
17
17
  ''' # END VERSION_JSON
18
18
 
@@ -0,0 +1,206 @@
1
+ """Generic, dependency-light seekable-stream helpers for lazy partial reads.
2
+
3
+ These are DRB-model-free: they operate on plain binary streams so any driver
4
+ can compose them without importing driver types.
5
+ """
6
+ import io
7
+ from collections import OrderedDict
8
+ from typing import Callable, Tuple
9
+
10
+
11
+ class SeekableWindow(io.RawIOBase):
12
+ """A read-only seekable view over a byte range of a parent seekable stream.
13
+
14
+ Exposes ``parent[offset:offset + length]`` as a standalone stream
15
+ positioned at 0. ``parent`` must be seekable. By default closing the window
16
+ closes ``parent`` too (set ``close_parent=False`` to keep it open).
17
+ """
18
+
19
+ def __init__(self, parent, offset: int, length: int,
20
+ close_parent: bool = True):
21
+ super().__init__()
22
+ self._parent = parent
23
+ self._offset = offset
24
+ self._length = length
25
+ self._pos = 0
26
+ self._close_parent = close_parent
27
+
28
+ def readable(self) -> bool:
29
+ return True
30
+
31
+ def seekable(self) -> bool:
32
+ return True
33
+
34
+ def seek(self, pos: int, whence: int = io.SEEK_SET) -> int:
35
+ if whence == io.SEEK_SET:
36
+ new = pos
37
+ elif whence == io.SEEK_CUR:
38
+ new = self._pos + pos
39
+ elif whence == io.SEEK_END:
40
+ new = self._length + pos
41
+ else:
42
+ raise ValueError(f'invalid whence: {whence}')
43
+ if new < 0:
44
+ raise OSError('negative seek position')
45
+ self._pos = new
46
+ return self._pos
47
+
48
+ def tell(self) -> int:
49
+ return self._pos
50
+
51
+ def read(self, size: int = -1) -> bytes:
52
+ remaining = self._length - self._pos
53
+ if remaining <= 0:
54
+ return b''
55
+ if size is None or size < 0:
56
+ size = remaining
57
+ size = min(size, remaining)
58
+ if size == 0:
59
+ return b''
60
+ self._parent.seek(self._offset + self._pos)
61
+ data = self._parent.read(size)
62
+ self._pos += len(data)
63
+ return data
64
+
65
+ def readinto(self, b: bytearray) -> int:
66
+ data = self.read(len(b))
67
+ n = len(data)
68
+ b[:n] = data
69
+ return n
70
+
71
+ def close(self) -> None:
72
+ if not self.closed and self._close_parent:
73
+ self._parent.close()
74
+ super().close()
75
+
76
+
77
+ class BlockCache:
78
+ """A bounded LRU cache of fixed-size byte blocks, shared across streams.
79
+
80
+ Blocks are keyed by ``(source_id, index)`` and are ``block_size`` bytes
81
+ each (the last block of a source may be shorter). Total residency is
82
+ bounded by ``max_bytes``; least-recently-used blocks are evicted first.
83
+ """
84
+
85
+ def __init__(self, block_size: int = 1 << 20,
86
+ max_bytes: int = 64 << 20):
87
+ self.block_size = block_size
88
+ self.max_bytes = max_bytes
89
+ self._blocks: 'OrderedDict[Tuple[str, int], bytes]' = OrderedDict()
90
+ self._total = 0
91
+
92
+ def total_bytes(self) -> int:
93
+ return self._total
94
+
95
+ def get_block(self, source_id: str, index: int,
96
+ fetch: Callable[[int, int], bytes]) -> bytes:
97
+ key = (source_id, index)
98
+ block = self._blocks.get(key)
99
+ if block is not None:
100
+ self._blocks.move_to_end(key)
101
+ return block
102
+ block = fetch(index * self.block_size, self.block_size)
103
+ self._blocks[key] = block
104
+ self._total += len(block)
105
+ self._evict()
106
+ return block
107
+
108
+ def _evict(self) -> None:
109
+ while self._total > self.max_bytes and len(self._blocks) > 1:
110
+ _, block = self._blocks.popitem(last=False)
111
+ self._total -= len(block)
112
+
113
+
114
+ class BlockCacheStream(io.RawIOBase):
115
+ """A seekable read-only stream serving ``parent`` through a ``BlockCache``.
116
+
117
+ ``parent`` must be seekable; ``size`` is its total byte length. Reads are
118
+ assembled from fixed-size blocks fetched (once) from ``parent`` and cached
119
+ in the shared ``cache`` under ``source_id``.
120
+ """
121
+
122
+ def __init__(self, parent, source_id: str, size: int,
123
+ cache: BlockCache):
124
+ super().__init__()
125
+ self._parent = parent
126
+ self._sid = source_id
127
+ self._size = size
128
+ self._cache = cache
129
+ self._pos = 0
130
+
131
+ def readable(self) -> bool:
132
+ return True
133
+
134
+ def seekable(self) -> bool:
135
+ return True
136
+
137
+ def seek(self, pos: int, whence: int = io.SEEK_SET) -> int:
138
+ if whence == io.SEEK_SET:
139
+ new = pos
140
+ elif whence == io.SEEK_CUR:
141
+ new = self._pos + pos
142
+ elif whence == io.SEEK_END:
143
+ new = self._size + pos
144
+ else:
145
+ raise ValueError(f'invalid whence: {whence}')
146
+ if new < 0:
147
+ raise OSError('negative seek position')
148
+ self._pos = new
149
+ return self._pos
150
+
151
+ def tell(self) -> int:
152
+ return self._pos
153
+
154
+ def _fetch(self, offset: int, length: int) -> bytes:
155
+ self._parent.seek(offset)
156
+ return self._parent.read(length)
157
+
158
+ def read(self, size: int = -1) -> bytes:
159
+ remaining = self._size - self._pos
160
+ if remaining <= 0:
161
+ return b''
162
+ if size is None or size < 0:
163
+ size = remaining
164
+ size = min(size, remaining)
165
+ out = bytearray()
166
+ bs = self._cache.block_size
167
+ while size > 0:
168
+ index = self._pos // bs
169
+ block = self._cache.get_block(self._sid, index, self._fetch)
170
+ start = self._pos - index * bs
171
+ piece = block[start:start + size]
172
+ if not piece:
173
+ break
174
+ out += piece
175
+ self._pos += len(piece)
176
+ size -= len(piece)
177
+ return bytes(out)
178
+
179
+ def readinto(self, b: bytearray) -> int:
180
+ data = self.read(len(b))
181
+ n = len(data)
182
+ b[:n] = data
183
+ return n
184
+
185
+ def close(self) -> None:
186
+ if not self.closed:
187
+ self._parent.close()
188
+ super().close()
189
+
190
+
191
+ def get_shared_cache(context: 'Context') -> BlockCache:
192
+ """Return the ``BlockCache`` stored in ``context``'s ``'cache'`` bucket,
193
+ creating it on first access.
194
+
195
+ This function is not resolver-specific: it merely gets-or-creates the
196
+ cache on whatever ``Context`` object is passed in. The actual sharing
197
+ scope is determined entirely by the caller — e.g. passing the same
198
+ archive node's context for every member of an archive shares one cache
199
+ across them.
200
+ """
201
+ bucket = context['cache']
202
+ cache = bucket.get('blocks')
203
+ if cache is None:
204
+ cache = BlockCache()
205
+ bucket['blocks'] = cache
206
+ return cache
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: drb
3
- Version: 2.6.2
3
+ Version: 2.7.0
4
4
  Summary: Data Request Broker
5
5
  Author: GAEL Systems
6
6
  Author-email: drb-python@gael.fr
@@ -59,6 +59,7 @@ drb/topics/xml/__init__.py
59
59
  drb/topics/xml/cortex.ttl
60
60
  drb/utils/__init__.py
61
61
  drb/utils/drb_python_script.py
62
+ drb/utils/io.py
62
63
  drb/utils/plugins.py
63
64
  drb/utils/url_security.py
64
65
  drb/utils/utils.py
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
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