chtypes 2.0.0.dev5__py3-none-any.whl → 2.0.0.dev6__py3-none-any.whl
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.
- chtypes/_ocifetch/_channel.py +28 -0
- chtypes/_ocifetch/_constants.py +7 -1
- chtypes/registry.py +83 -22
- {chtypes-2.0.0.dev5.dist-info → chtypes-2.0.0.dev6.dist-info}/METADATA +1 -1
- {chtypes-2.0.0.dev5.dist-info → chtypes-2.0.0.dev6.dist-info}/RECORD +8 -8
- {chtypes-2.0.0.dev5.dist-info → chtypes-2.0.0.dev6.dist-info}/WHEEL +0 -0
- {chtypes-2.0.0.dev5.dist-info → chtypes-2.0.0.dev6.dist-info}/entry_points.txt +0 -0
- {chtypes-2.0.0.dev5.dist-info → chtypes-2.0.0.dev6.dist-info}/licenses/LICENSE +0 -0
chtypes/_ocifetch/_channel.py
CHANGED
|
@@ -79,6 +79,7 @@ __all__ = [
|
|
|
79
79
|
"visible",
|
|
80
80
|
"use_dev_channel_for_tests",
|
|
81
81
|
"use_fetch_v1_for_tests",
|
|
82
|
+
"use_prod_v2_for_tests",
|
|
82
83
|
]
|
|
83
84
|
|
|
84
85
|
# The dev channel's registry and key (spec/abi-v2/docs.md, rule r6).
|
|
@@ -165,6 +166,25 @@ FETCH_V1_CHANNEL: Final = Channel(
|
|
|
165
166
|
pinnable=True,
|
|
166
167
|
)
|
|
167
168
|
|
|
169
|
+
# The production generation-2 channel a 2.0.0 SDK speaks after the lock: the v1
|
|
170
|
+
# contract with v2 values, from the generated constants (docs/guides/fetch-v1.md,
|
|
171
|
+
# "Generation 2 after the lock"). It trusts the release key, honors every
|
|
172
|
+
# override and pin, and has no alias step. NOT the default: only
|
|
173
|
+
# use_prod_v2_for_tests selects it, until the lock change makes it active()'s
|
|
174
|
+
# fallback.
|
|
175
|
+
PROD_V2_CHANNEL: Final = Channel(
|
|
176
|
+
name=C.PROD_V2_NAME,
|
|
177
|
+
abi=C.PROD_V2_ABI_GENERATION,
|
|
178
|
+
record_schema=C.PROD_V2_RECORD_SCHEMA,
|
|
179
|
+
root_leaf=C.PROD_V2_CACHE_DIR,
|
|
180
|
+
subroot=C.PROD_V2_CACHE_DIR,
|
|
181
|
+
system_dirs=C.PROD_V2_SYSTEM_DIRS,
|
|
182
|
+
bases=C.PROD_V2_BASES,
|
|
183
|
+
keys=C.RELEASE_KEYS,
|
|
184
|
+
overridable=True,
|
|
185
|
+
pinnable=True,
|
|
186
|
+
)
|
|
187
|
+
|
|
168
188
|
_lock = threading.Lock()
|
|
169
189
|
_current: Channel | None = None
|
|
170
190
|
|
|
@@ -224,6 +244,14 @@ def use_fetch_v1_for_tests() -> Callable[[], None]:
|
|
|
224
244
|
return _use(FETCH_V1_CHANNEL)
|
|
225
245
|
|
|
226
246
|
|
|
247
|
+
def use_prod_v2_for_tests() -> Callable[[], None]:
|
|
248
|
+
"""Make this TEST run speak the production generation-2 channel
|
|
249
|
+
(`PROD_V2_CHANNEL`): the v1 contract with abi 2, schema-2 records and the
|
|
250
|
+
`v2` subroot. Returns the restore function; raises outside a test run."""
|
|
251
|
+
_test_only("use_prod_v2_for_tests")
|
|
252
|
+
return _use(PROD_V2_CHANNEL)
|
|
253
|
+
|
|
254
|
+
|
|
227
255
|
def allow_overrides_for_tests() -> Callable[[], None]:
|
|
228
256
|
"""Make this TEST run's dev channel honor the base, trust and unsigned
|
|
229
257
|
overrides, so a test can reach a fixture registry signed with the test key;
|
chtypes/_ocifetch/_constants.py
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Code generated by scripts/fetch-v1/gen-constants.py from
|
|
2
2
|
# spec/fetch-v1/constants.json. DO NOT EDIT.
|
|
3
|
-
# Source sha256:
|
|
3
|
+
# Source sha256: 82afa8d6cba96c10b5945c6f7c1c8360a504cc8ac6231e74017cc6c20b908df6
|
|
4
4
|
"""The v1 fetch constants, generated: see docs/guides/fetch-v1.md."""
|
|
5
5
|
|
|
6
6
|
from __future__ import annotations
|
|
@@ -101,6 +101,12 @@ RETIRED_MESSAGE_MAX_CODE_POINTS: Final[int] = 256
|
|
|
101
101
|
|
|
102
102
|
CACHE_ROOT_TEMPLATE: Final[str] = "${XDG_CACHE_HOME:-$HOME/.cache}/chtypes/v1"
|
|
103
103
|
SYSTEM_CACHE_DIRS: Final[tuple[str, ...]] = ("/usr/local/share/chtypes/v1", "/opt/chtypes/v1")
|
|
104
|
+
PROD_V2_NAME: Final[str] = "v2"
|
|
105
|
+
PROD_V2_ABI_GENERATION: Final[int] = 2
|
|
106
|
+
PROD_V2_RECORD_SCHEMA: Final[int] = 2
|
|
107
|
+
PROD_V2_CACHE_DIR: Final[str] = "v2"
|
|
108
|
+
PROD_V2_BASES: Final[tuple[str, ...]] = ("https://registry.wavehouse.dev/chtypes/v2",)
|
|
109
|
+
PROD_V2_SYSTEM_DIRS: Final[tuple[str, ...]] = ("/usr/local/share/chtypes/v2", "/opt/chtypes/v2")
|
|
104
110
|
CACHE_UNPACKED_DIR: Final[str] = "unpacked/sha256"
|
|
105
111
|
CACHE_VERIFIED_RECORD: Final[str] = "verified.json"
|
|
106
112
|
CACHE_ANNOTATION_PREFIX: Final[str] = "dev.wavehouse.chtypes."
|
chtypes/registry.py
CHANGED
|
@@ -15,13 +15,19 @@ The sequence of `for_version(request)`:
|
|
|
15
15
|
Construction opens nothing. The binding orders and matches no versions itself:
|
|
16
16
|
which installed build a floating request means, and the spelling rules, are the
|
|
17
17
|
fetch layer's.
|
|
18
|
+
|
|
19
|
+
Opens of different requests never wait for each other's fetch (public issue
|
|
20
|
+
#491): the registry's lock guards its memo and the attempts in progress, and is
|
|
21
|
+
never held across steps 2 to 5. Concurrent opens of one request share one
|
|
22
|
+
attempt, and so one fetch, and each gets that attempt's `Library` or its error;
|
|
23
|
+
a failed attempt is never remembered, so the next open starts a new one.
|
|
18
24
|
"""
|
|
19
25
|
|
|
20
26
|
from __future__ import annotations
|
|
21
27
|
|
|
22
28
|
import os
|
|
23
29
|
import threading
|
|
24
|
-
from collections.abc import Sequence
|
|
30
|
+
from collections.abc import Callable, Sequence
|
|
25
31
|
from dataclasses import dataclass
|
|
26
32
|
from pathlib import Path
|
|
27
33
|
|
|
@@ -168,6 +174,19 @@ def _wrap(exc: FetchError) -> errors.ArtifactError:
|
|
|
168
174
|
return wrapped
|
|
169
175
|
|
|
170
176
|
|
|
177
|
+
class _Flight:
|
|
178
|
+
"""One attempt to open one request: the installed lookup, the fetch when
|
|
179
|
+
there is one, and the load. Every open of that request made while it is in
|
|
180
|
+
progress waits on it and gets its answer."""
|
|
181
|
+
|
|
182
|
+
__slots__ = ("done", "error", "library")
|
|
183
|
+
|
|
184
|
+
def __init__(self) -> None:
|
|
185
|
+
self.done = threading.Event()
|
|
186
|
+
self.library: Library | None = None
|
|
187
|
+
self.error: BaseException | None = None
|
|
188
|
+
|
|
189
|
+
|
|
171
190
|
class Registry:
|
|
172
191
|
"""Opens versions. Safe across threads. `autofetch` defaults to
|
|
173
192
|
`CHTYPES_AUTOFETCH`, and is off when that is unset.
|
|
@@ -175,6 +194,9 @@ class Registry:
|
|
|
175
194
|
Construction opens nothing: only `for_version` and `preload` open an
|
|
176
195
|
artifact. `preload` opens each listed request through the loader at
|
|
177
196
|
construction, in list order, and never fetches, even with autofetch on.
|
|
197
|
+
|
|
198
|
+
An open never waits for another request's fetch, and concurrent opens of
|
|
199
|
+
one request share one fetch (public issue #491).
|
|
178
200
|
"""
|
|
179
201
|
|
|
180
202
|
def __init__(
|
|
@@ -189,8 +211,14 @@ class Registry:
|
|
|
189
211
|
env = os.environ.get(_fetch_constants.ENV_AUTOFETCH_NAME, "")
|
|
190
212
|
autofetch = env.strip().lower() in _TRUTHY
|
|
191
213
|
self._autofetch = autofetch
|
|
192
|
-
|
|
214
|
+
# Guards the memo and the attempts in progress, never a lookup, a fetch
|
|
215
|
+
# or a load.
|
|
216
|
+
self._lock = threading.Lock()
|
|
193
217
|
self._memo: dict[str, Library] = {}
|
|
218
|
+
self._flights: dict[str, _Flight] = {}
|
|
219
|
+
# A test hook, None outside tests: called each time an open starts
|
|
220
|
+
# waiting on an attempt, its own or another open's.
|
|
221
|
+
self._on_wait: Callable[[str], None] | None = None
|
|
194
222
|
if isinstance(preload, str):
|
|
195
223
|
raise TypeError("preload must be a sequence of requests, not a single string")
|
|
196
224
|
for request in preload:
|
|
@@ -221,30 +249,63 @@ class Registry:
|
|
|
221
249
|
return tuple(seen)
|
|
222
250
|
|
|
223
251
|
def _open(self, request: str, *, allow_fetch: bool) -> Library:
|
|
252
|
+
with self._lock:
|
|
253
|
+
hit = self._memo.get(request)
|
|
254
|
+
if hit is not None:
|
|
255
|
+
return hit
|
|
256
|
+
# A refused version spelling is the caller's own misuse, refused before
|
|
257
|
+
# anything is attempted, and unlocks nothing.
|
|
258
|
+
try:
|
|
259
|
+
fetch_request = Request(request)
|
|
260
|
+
except ValueError as exc:
|
|
261
|
+
raise errors.misuse(str(exc)) from None
|
|
262
|
+
# So is a pinning request on the dev channel (rule r6).
|
|
263
|
+
_refuse_pinning(self._fetch._to_options())
|
|
224
264
|
with self._lock:
|
|
225
265
|
hit = self._memo.get(request)
|
|
226
266
|
if hit is not None:
|
|
227
267
|
return hit
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
268
|
+
flight = self._flights.get(request)
|
|
269
|
+
lead = flight is None
|
|
270
|
+
if flight is None:
|
|
271
|
+
flight = self._flights[request] = _Flight()
|
|
272
|
+
on_wait = self._on_wait
|
|
273
|
+
if on_wait is not None:
|
|
274
|
+
on_wait(request)
|
|
275
|
+
if lead:
|
|
276
|
+
self._attempt(flight, request, fetch_request, allow_fetch)
|
|
277
|
+
else:
|
|
278
|
+
flight.done.wait()
|
|
279
|
+
if flight.error is not None:
|
|
280
|
+
raise flight.error
|
|
281
|
+
assert flight.library is not None
|
|
282
|
+
return flight.library
|
|
283
|
+
|
|
284
|
+
def _attempt(
|
|
285
|
+
self, flight: _Flight, request: str, fetch_request: Request, allow_fetch: bool
|
|
286
|
+
) -> None:
|
|
287
|
+
"""Run an attempt on the leading open's thread, with no lock held, then
|
|
288
|
+
release every open waiting on it. An attempt that tried a load and
|
|
289
|
+
failed unlocks the setup record while no image has completed load step
|
|
290
|
+
7, whatever failed: the resolve, the fetch, the signature or any load
|
|
291
|
+
step (bindings-v1.md section 6, rule 4). It is never remembered."""
|
|
292
|
+
began = _setup.generation()
|
|
293
|
+
library: Library | None = None
|
|
294
|
+
error: BaseException | None = None
|
|
295
|
+
try:
|
|
296
|
+
library = self._resolve_and_open(request, fetch_request, allow_fetch)
|
|
297
|
+
except Exception as exc:
|
|
298
|
+
_setup.open_failed(began)
|
|
299
|
+
error = exc
|
|
300
|
+
except BaseException as exc:
|
|
301
|
+
error = exc
|
|
302
|
+
with self._lock:
|
|
303
|
+
del self._flights[request]
|
|
304
|
+
if error is None:
|
|
305
|
+
assert library is not None
|
|
306
|
+
self._memo[request] = library
|
|
307
|
+
flight.library, flight.error = library, error
|
|
308
|
+
flight.done.set()
|
|
248
309
|
|
|
249
310
|
def _resolve_and_open(self, request: str, fetch_request: Request, allow_fetch: bool) -> Library:
|
|
250
311
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: chtypes
|
|
3
|
-
Version: 2.0.0.
|
|
3
|
+
Version: 2.0.0.dev6
|
|
4
4
|
Summary: Python binding for the chtypes artifacts: ClickHouse's own type system, per version, behind the frozen chs_* C ABI
|
|
5
5
|
Project-URL: Homepage, https://github.com/wave-rf/chtypes
|
|
6
6
|
Project-URL: Repository, https://github.com/wave-rf/chtypes
|
|
@@ -8,7 +8,7 @@ chtypes/_setup.py,sha256=n84T0hFmXu_fdnXQIFhk3dMVL0_-yhfdRZsqCXTLzzg,6114
|
|
|
8
8
|
chtypes/errors.py,sha256=7gDi9Ij8yptrr9E0LZyA2XkeaFFVyZoQMVQjQj6mn0s,9936
|
|
9
9
|
chtypes/library.py,sha256=G6DJFiRuv8--JARxfiSNEqeFLkafaMs_n9nG-IwoC74,17878
|
|
10
10
|
chtypes/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
|
-
chtypes/registry.py,sha256=
|
|
11
|
+
chtypes/registry.py,sha256=ApkHjOx4jBxeKJCZ7aTsPDJCWFnSd6rDRLfXam4ddQg,16275
|
|
12
12
|
chtypes/results.py,sha256=gue7f4pqnpvXlSteYqhmqU1ZuAYCD7p4AgTiuYWpgYY,12591
|
|
13
13
|
chtypes/_abi2/__init__.py,sha256=d3i7_iUDMFT1jg49vRQz1SMH6oseYZHUR0oPt6aSTiY,1042
|
|
14
14
|
chtypes/_abi2/_decls.py,sha256=tGj_gOkMsw9fv8lWBXHUMn6dfYqpkta_nq1BhT6p4Dk,38454
|
|
@@ -17,8 +17,8 @@ chtypes/_abi2/_errors.py,sha256=wRE9M0oYtJz_9izQqpEBh5571M_1QzGWBoJ3pJTykWw,761
|
|
|
17
17
|
chtypes/_abi2/_loader.py,sha256=VMWrbWMp9Uq3K-7a219lfqAmSmBlD2hcB6WDJgG8XG0,12514
|
|
18
18
|
chtypes/_abi2/_vocab.py,sha256=6Ly15gQ1Vf3SP8hDSWCg1jnwVEURCBWSj9LZgv23xfA,17442
|
|
19
19
|
chtypes/_ocifetch/__init__.py,sha256=enfPOKkqP4kqAKqckBGWXN1OQsiYo9ngDP-wzG0zn2I,1484
|
|
20
|
-
chtypes/_ocifetch/_channel.py,sha256=
|
|
21
|
-
chtypes/_ocifetch/_constants.py,sha256=
|
|
20
|
+
chtypes/_ocifetch/_channel.py,sha256=YEt6qlhr-AMFhSHefFvS5GQJ30-Qh4PAbGN6xnHZwxU,20217
|
|
21
|
+
chtypes/_ocifetch/_constants.py,sha256=Lt7hrSxFr5L2y87wsw33bbCekEwdq8wKn8N3i_r79o8,5974
|
|
22
22
|
chtypes/_ocifetch/_dsse.py,sha256=0RaFJaG1jhXr1uPfuHxm7yAn6viNzYhfCRUf-sW5SvQ,9333
|
|
23
23
|
chtypes/_ocifetch/_ensure.py,sha256=rI_xj0dccct7wMz0DwHoJTAB-yGVYFkLZ2Z0qRXuR30,63612
|
|
24
24
|
chtypes/_ocifetch/_errors.py,sha256=TTYpwhvZ7MyD9Ssg5js8_YB8Fl30rYBPlENyAetqEbQ,7129
|
|
@@ -31,8 +31,8 @@ chtypes/_ocifetch/_oci.py,sha256=UdA8QGTh1O27DBYRf5UxsevjgI52IecQlEf9IO6Y0A4,139
|
|
|
31
31
|
chtypes/_ocifetch/_referrers.py,sha256=J2b4gN6vryz_IzYHxrd2Tp-tQO9Cz766rZtKgCVcKqA,6008
|
|
32
32
|
chtypes/_ocifetch/_retired.py,sha256=MQ6nbWLJw50IZYY1VfM6AiCZ4BySK0GVkGVOtAXaq3Y,3060
|
|
33
33
|
chtypes/_ocifetch/_unpack.py,sha256=Cn4-up63KL63L8pnkS5zwJ6VbbHPSigpCnmOdcHJ4RI,5609
|
|
34
|
-
chtypes-2.0.0.
|
|
35
|
-
chtypes-2.0.0.
|
|
36
|
-
chtypes-2.0.0.
|
|
37
|
-
chtypes-2.0.0.
|
|
38
|
-
chtypes-2.0.0.
|
|
34
|
+
chtypes-2.0.0.dev6.dist-info/METADATA,sha256=T0boAAXpcSjeW7OqcCM0WihNHOX7ZRGU4ePoQnAlL-I,11280
|
|
35
|
+
chtypes-2.0.0.dev6.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
36
|
+
chtypes-2.0.0.dev6.dist-info/entry_points.txt,sha256=TdNcluWBR0VOt5mVFROsp-NiVPAdR3EHo0UsHlMC0r0,50
|
|
37
|
+
chtypes-2.0.0.dev6.dist-info/licenses/LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
|
|
38
|
+
chtypes-2.0.0.dev6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|