arraybridge 0.3.4__py3-none-any.whl → 0.3.6__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.
- arraybridge/__init__.py +1 -1
- arraybridge/decorators.py +41 -16
- {arraybridge-0.3.4.dist-info → arraybridge-0.3.6.dist-info}/METADATA +2 -1
- {arraybridge-0.3.4.dist-info → arraybridge-0.3.6.dist-info}/RECORD +6 -6
- {arraybridge-0.3.4.dist-info → arraybridge-0.3.6.dist-info}/WHEEL +0 -0
- {arraybridge-0.3.4.dist-info → arraybridge-0.3.6.dist-info}/licenses/LICENSE +0 -0
arraybridge/__init__.py
CHANGED
arraybridge/decorators.py
CHANGED
|
@@ -82,11 +82,13 @@ class DtypeConversionConfig(RuntimeParameterDeclarationABC):
|
|
|
82
82
|
return DtypeConversionConfig
|
|
83
83
|
|
|
84
84
|
@classmethod
|
|
85
|
-
def parameter(
|
|
85
|
+
def parameter(
|
|
86
|
+
cls, *, default_value: "DtypeConversionConfig | None" = None
|
|
87
|
+
) -> inspect.Parameter:
|
|
86
88
|
return inspect.Parameter(
|
|
87
89
|
cls.require_parameter_name(),
|
|
88
90
|
inspect.Parameter.KEYWORD_ONLY,
|
|
89
|
-
default=cls.default_value(),
|
|
91
|
+
default=cls.default_value() if default_value is None else default_value,
|
|
90
92
|
annotation=cls.annotation_type(),
|
|
91
93
|
)
|
|
92
94
|
|
|
@@ -264,12 +266,30 @@ class KeywordOnlySignatureExtension:
|
|
|
264
266
|
return len(parameters)
|
|
265
267
|
|
|
266
268
|
|
|
267
|
-
|
|
268
|
-
|
|
269
|
+
class ThreadGPUContextStorage(threading.local):
|
|
270
|
+
"""Declare the existing native thread-local context slot and its type."""
|
|
271
|
+
|
|
272
|
+
context: "ThreadGPUContext | None" = None
|
|
269
273
|
|
|
270
274
|
|
|
271
275
|
class ThreadGPUContext:
|
|
272
|
-
"""
|
|
276
|
+
"""Runtime-owned thread-local streams keyed by framework/device identity.
|
|
277
|
+
|
|
278
|
+
Keep the runtime handle on its importable owner, not in decorator function
|
|
279
|
+
globals. A retained, unpublished decorated callable is serialized by value;
|
|
280
|
+
its durable closure must not pull a ``threading.local`` into history.
|
|
281
|
+
"""
|
|
282
|
+
|
|
283
|
+
_contexts: ClassVar[ThreadGPUContextStorage] = ThreadGPUContextStorage()
|
|
284
|
+
|
|
285
|
+
@classmethod
|
|
286
|
+
def current(cls) -> "ThreadGPUContext":
|
|
287
|
+
"""Return this thread's runtime context without serializing its handle."""
|
|
288
|
+
context = cls._contexts.context
|
|
289
|
+
if context is None:
|
|
290
|
+
context = cls()
|
|
291
|
+
cls._contexts.context = context
|
|
292
|
+
return context
|
|
273
293
|
|
|
274
294
|
def __init__(self):
|
|
275
295
|
self._streams: dict[tuple[MemoryType, int], Any] = {}
|
|
@@ -301,13 +321,6 @@ class ThreadGPUContext:
|
|
|
301
321
|
return device_id, self._streams[key]
|
|
302
322
|
|
|
303
323
|
|
|
304
|
-
def _get_thread_gpu_context():
|
|
305
|
-
"""Get or create thread-local GPU context."""
|
|
306
|
-
if not hasattr(_thread_gpu_contexts, "context"):
|
|
307
|
-
_thread_gpu_contexts.context = ThreadGPUContext()
|
|
308
|
-
return _thread_gpu_contexts.context
|
|
309
|
-
|
|
310
|
-
|
|
311
324
|
def memory_types(
|
|
312
325
|
input_type: str | MemoryType,
|
|
313
326
|
output_type: str | MemoryType,
|
|
@@ -352,6 +365,7 @@ def wrap_dtype_preserving_callable(
|
|
|
352
365
|
mem_type: MemoryType,
|
|
353
366
|
*,
|
|
354
367
|
slice_by_slice_default: bool = False,
|
|
368
|
+
dtype_config_default: DtypeConversionConfig | None = None,
|
|
355
369
|
):
|
|
356
370
|
"""
|
|
357
371
|
Return a callable with ArrayBridge dtype and slice controls.
|
|
@@ -363,18 +377,25 @@ def wrap_dtype_preserving_callable(
|
|
|
363
377
|
input_memory_type = MemoryType(MemoryContractAttribute.INPUT.read(func, mem_type.value))
|
|
364
378
|
output_memory_type = MemoryType(MemoryContractAttribute.OUTPUT.read(func, mem_type.value))
|
|
365
379
|
scale_func = output_memory_type.scale_dtype
|
|
380
|
+
default_dtype_config = (
|
|
381
|
+
DtypeConversionConfig.default_value()
|
|
382
|
+
if dtype_config_default is None
|
|
383
|
+
else dtype_config_default
|
|
384
|
+
)
|
|
385
|
+
if not isinstance(default_dtype_config, DtypeConversionConfig):
|
|
386
|
+
raise TypeError("Callable dtype default must be a DtypeConversionConfig.")
|
|
366
387
|
|
|
367
388
|
@functools.wraps(func)
|
|
368
389
|
def dtype_wrapper(image, *args, **kwargs):
|
|
369
390
|
# Pipeline runtimes may inject dtype_config; direct calls use the same
|
|
370
|
-
# preserve-input
|
|
391
|
+
# callable-owned default explicitly (preserve-input when undeclared).
|
|
371
392
|
slice_by_slice = kwargs.pop(
|
|
372
393
|
SliceBySliceRuntimeParameter.require_parameter_name(),
|
|
373
394
|
slice_by_slice_default,
|
|
374
395
|
)
|
|
375
396
|
dtype_config: DtypeConversionConfig = kwargs.pop(
|
|
376
397
|
DtypeConversionConfig.require_parameter_name(),
|
|
377
|
-
|
|
398
|
+
default_dtype_config,
|
|
378
399
|
)
|
|
379
400
|
dtype_conversion = dtype_config.default_dtype_conversion
|
|
380
401
|
|
|
@@ -424,7 +445,7 @@ def wrap_dtype_preserving_callable(
|
|
|
424
445
|
)
|
|
425
446
|
)
|
|
426
447
|
dtype_signature = KeywordOnlySignatureExtension(dtype_signature).with_parameter(
|
|
427
|
-
DtypeConversionConfig.parameter()
|
|
448
|
+
DtypeConversionConfig.parameter(default_value=default_dtype_config)
|
|
428
449
|
)
|
|
429
450
|
setattr(dtype_wrapper, "__signature__", dtype_signature)
|
|
430
451
|
|
|
@@ -461,7 +482,7 @@ def _create_gpu_wrapper(func, mem_type: MemoryType, oom_recovery: bool):
|
|
|
461
482
|
# Check if GPU is available for this framework
|
|
462
483
|
if framework is not None and mem_type.available_device_ids(framework):
|
|
463
484
|
# Get thread-local context
|
|
464
|
-
ctx =
|
|
485
|
+
ctx = ThreadGPUContext.current()
|
|
465
486
|
|
|
466
487
|
device_id, stream = ctx.stream_for(mem_type, framework)
|
|
467
488
|
|
|
@@ -510,6 +531,7 @@ def _create_memory_decorator(mem_type: MemoryType):
|
|
|
510
531
|
oom_recovery=True,
|
|
511
532
|
contract=None,
|
|
512
533
|
slice_by_slice_default=False,
|
|
534
|
+
dtype_config_default: DtypeConversionConfig | None = None,
|
|
513
535
|
):
|
|
514
536
|
"""
|
|
515
537
|
Decorator for {mem_type} memory type functions.
|
|
@@ -521,6 +543,8 @@ def _create_memory_decorator(mem_type: MemoryType):
|
|
|
521
543
|
oom_recovery: Enable automatic OOM recovery (default: True)
|
|
522
544
|
contract: Optional validation function for outputs
|
|
523
545
|
slice_by_slice_default: Default for the decorator-owned slice control
|
|
546
|
+
dtype_config_default: Callable-owned dtype policy for direct calls;
|
|
547
|
+
explicit runtime dtype_config still overrides this default.
|
|
524
548
|
|
|
525
549
|
Returns:
|
|
526
550
|
Decorated function with memory type metadata and dtype preservation
|
|
@@ -538,6 +562,7 @@ def _create_memory_decorator(mem_type: MemoryType):
|
|
|
538
562
|
func,
|
|
539
563
|
mem_type,
|
|
540
564
|
slice_by_slice_default=slice_by_slice_default,
|
|
565
|
+
dtype_config_default=dtype_config_default,
|
|
541
566
|
)
|
|
542
567
|
|
|
543
568
|
# Apply GPU wrapper if this is a GPU memory type
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arraybridge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: Unified API for NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto with automatic memory type conversion
|
|
5
5
|
Project-URL: Homepage, https://github.com/OpenHCSDev/arraybridge
|
|
6
6
|
Project-URL: Documentation, https://arraybridge.readthedocs.io
|
|
@@ -36,6 +36,7 @@ Requires-Dist: cupy>=10.0; extra == 'cupy'
|
|
|
36
36
|
Provides-Extra: dev
|
|
37
37
|
Requires-Dist: black>=23.0; extra == 'dev'
|
|
38
38
|
Requires-Dist: build>=1.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: dill>=0.3.8; extra == 'dev'
|
|
39
40
|
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
40
41
|
Requires-Dist: packaging>=23.0; extra == 'dev'
|
|
41
42
|
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
arraybridge/__init__.py,sha256=
|
|
1
|
+
arraybridge/__init__.py,sha256=rhst2HuRsZE1bp4f23SjK6cTHNpjQUAsSnqgh9R6QUA,3184
|
|
2
2
|
arraybridge/array_geometry.py,sha256=CopfGmFVKwV5l-lOTImhm1YVh18weUng0ReEF58qlPI,1689
|
|
3
3
|
arraybridge/array_operations.py,sha256=fp69o9BYcCzfhmLcWrH68SVGSfPL3nb6Cty-Amd_oQM,13082
|
|
4
4
|
arraybridge/array_payload.py,sha256=6_jJwPRya0MHrUNSA9kXPlTISpLa0G74rqDValGXKx4,1079
|
|
5
5
|
arraybridge/converters.py,sha256=q44E6Pg1rJz8yq6WQIPLOZPv1lqqcUcEG4Gh4D5M1_o,2649
|
|
6
6
|
arraybridge/converters_registry.py,sha256=_hHtbd-3SMIKUw8fvNu3twPWJY7qHyNyQ_NhVp3eSHQ,5647
|
|
7
|
-
arraybridge/decorators.py,sha256=
|
|
7
|
+
arraybridge/decorators.py,sha256=KPm_R3C9TMHvNARf3vKAZQY-3gKSlvYrimxBQMyI5A4,21271
|
|
8
8
|
arraybridge/dtype_scaling.py,sha256=KDgYyCvxgsQXLJJl_bs5nH46zQimsA7c1Olv6xJ2z1o,831
|
|
9
9
|
arraybridge/exceptions.py,sha256=fhej5ZS39QcBFWzNeNYjoqeLVnOgwwp-cWIme25jyuo,752
|
|
10
10
|
arraybridge/framework_config.py,sha256=5yTTt9NWcwzKDMXbc-fqCdiFl-piKOt3SUnxmRXXCQk,744
|
|
@@ -15,7 +15,7 @@ arraybridge/slice_processing.py,sha256=5R10OmHW8BSbJFwT1URd2Sz3P15o5EhaI2VnVUUIv
|
|
|
15
15
|
arraybridge/stack_utils.py,sha256=FVikN0XG-Xryw-1p9MaSRUTZet7kLcy0gTEERSjc9r4,6915
|
|
16
16
|
arraybridge/types.py,sha256=e5R2DVflQAjXrfTk033KRdiiwoip3IQAvgDCYUjPdiQ,35807
|
|
17
17
|
arraybridge/utils.py,sha256=RqThtYScPEOEQG491dA8b_VvUTjgcFhwLbh0erQu5Ns,4833
|
|
18
|
-
arraybridge-0.3.
|
|
19
|
-
arraybridge-0.3.
|
|
20
|
-
arraybridge-0.3.
|
|
21
|
-
arraybridge-0.3.
|
|
18
|
+
arraybridge-0.3.6.dist-info/METADATA,sha256=uOSPAN8b0foxSeEJslCFyv0VhJR7suC1TWL9RBCrLTo,5318
|
|
19
|
+
arraybridge-0.3.6.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
20
|
+
arraybridge-0.3.6.dist-info/licenses/LICENSE,sha256=xagEoeTAj1WT64RmyR3E6HH-eTGdgXN6gqPMUUt7L_Y,1070
|
|
21
|
+
arraybridge-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|