arraybridge 0.3.0__tar.gz → 0.3.2__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 (86) hide show
  1. {arraybridge-0.3.0 → arraybridge-0.3.2}/PKG-INFO +2 -1
  2. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/api_reference.rst +5 -0
  3. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/conf.py +1 -1
  4. {arraybridge-0.3.0 → arraybridge-0.3.2}/pyproject.toml +6 -2
  5. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/__init__.py +3 -1
  6. arraybridge-0.3.2/src/arraybridge/array_geometry.py +57 -0
  7. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/decorators.py +3 -2
  8. arraybridge-0.3.2/tests/test_array_geometry.py +53 -0
  9. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_decorators.py +8 -0
  10. {arraybridge-0.3.0 → arraybridge-0.3.2}/.github/workflows/ci.yml +0 -0
  11. {arraybridge-0.3.0 → arraybridge-0.3.2}/.github/workflows/coverage-pages.yml +0 -0
  12. {arraybridge-0.3.0 → arraybridge-0.3.2}/.github/workflows/gpu-tests.yml +0 -0
  13. {arraybridge-0.3.0 → arraybridge-0.3.2}/.github/workflows/publish.yml +0 -0
  14. {arraybridge-0.3.0 → arraybridge-0.3.2}/.gitignore +0 -0
  15. {arraybridge-0.3.0 → arraybridge-0.3.2}/.readthedocs.yml +0 -0
  16. {arraybridge-0.3.0 → arraybridge-0.3.2}/ADDING_NEW_FRAMEWORKS.md +0 -0
  17. {arraybridge-0.3.0 → arraybridge-0.3.2}/CONTRIBUTING.md +0 -0
  18. {arraybridge-0.3.0 → arraybridge-0.3.2}/LICENSE +0 -0
  19. {arraybridge-0.3.0 → arraybridge-0.3.2}/README.md +0 -0
  20. {arraybridge-0.3.0 → arraybridge-0.3.2}/TESTING.md +0 -0
  21. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/Makefile +0 -0
  22. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/CI_ARTIFACT_UPDATE.md +0 -0
  23. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/CI_CUPY_FIX.md +0 -0
  24. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/CI_IMPROVEMENTS.md +0 -0
  25. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/CONFLICT_VISUALIZATION.md +0 -0
  26. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/COVERAGE_AUDIT_PLAN.md +0 -0
  27. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/DEPLOYMENT_SUMMARY.md +0 -0
  28. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/GPU_TESTING_SETUP.md +0 -0
  29. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/MERGE_CONFLICT_RESOLUTION.md +0 -0
  30. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/MIGRATION_SUMMARY.md +0 -0
  31. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/QUICK_FIX_GUIDE.txt +0 -0
  32. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/README.md +0 -0
  33. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/archive/RESOLVED_FILES.md +0 -0
  34. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/ci-cd.md +0 -0
  35. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/.gitignore +0 -0
  36. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/Makefile +0 -0
  37. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/README.md +0 -0
  38. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/advanced_topics.rst +0 -0
  39. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/ci-cd.rst +0 -0
  40. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/contributing.rst +0 -0
  41. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/converters.rst +0 -0
  42. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/decorators.rst +0 -0
  43. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/examples/basic_conversion.rst +0 -0
  44. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/examples/decorators.rst +0 -0
  45. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/examples/index.rst +0 -0
  46. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/examples/multi_framework.rst +0 -0
  47. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/gpu_features.rst +0 -0
  48. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/index.rst +0 -0
  49. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/installation.rst +0 -0
  50. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/quickstart.rst +0 -0
  51. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/stack_utils.rst +0 -0
  52. {arraybridge-0.3.0 → arraybridge-0.3.2}/docs/source/user_guide.rst +0 -0
  53. {arraybridge-0.3.0 → arraybridge-0.3.2}/paper.bib +0 -0
  54. {arraybridge-0.3.0 → arraybridge-0.3.2}/paper.md +0 -0
  55. {arraybridge-0.3.0 → arraybridge-0.3.2}/scripts/release.py +0 -0
  56. {arraybridge-0.3.0 → arraybridge-0.3.2}/scripts/update_version.py +0 -0
  57. {arraybridge-0.3.0 → arraybridge-0.3.2}/scripts/verify_release_ready.py +0 -0
  58. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/array_operations.py +0 -0
  59. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/array_payload.py +0 -0
  60. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/converters.py +0 -0
  61. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/converters_registry.py +0 -0
  62. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/dtype_scaling.py +0 -0
  63. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/exceptions.py +0 -0
  64. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/framework_config.py +0 -0
  65. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/framework_ops.py +0 -0
  66. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/gpu_cleanup.py +0 -0
  67. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/oom_recovery.py +0 -0
  68. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/slice_processing.py +0 -0
  69. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/stack_utils.py +0 -0
  70. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/types.py +0 -0
  71. {arraybridge-0.3.0 → arraybridge-0.3.2}/src/arraybridge/utils.py +0 -0
  72. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/__init__.py +0 -0
  73. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/conftest.py +0 -0
  74. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_converters.py +0 -0
  75. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_converters_registry.py +0 -0
  76. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_dtype_scaling.py +0 -0
  77. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_exceptions.py +0 -0
  78. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_framework_config.py +0 -0
  79. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_gpu_cleanup.py +0 -0
  80. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_integration.py +0 -0
  81. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_oom_recovery.py +0 -0
  82. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_registry_integration.py +0 -0
  83. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_slice_processing.py +0 -0
  84. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_stack_utils.py +0 -0
  85. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_types.py +0 -0
  86. {arraybridge-0.3.0 → arraybridge-0.3.2}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: arraybridge
3
- Version: 0.3.0
3
+ Version: 0.3.2
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
@@ -23,6 +23,7 @@ Classifier: Topic :: Software Development :: Libraries :: Python Modules
23
23
  Requires-Python: >=3.10
24
24
  Requires-Dist: metaclass-registry>=0.1.5
25
25
  Requires-Dist: numpy>=1.20
26
+ Requires-Dist: python-introspect>=0.1.11
26
27
  Provides-Extra: all
27
28
  Requires-Dist: cupy>=10.0; extra == 'all'
28
29
  Requires-Dist: jax>=0.3; extra == 'all'
@@ -12,6 +12,11 @@ Public imports
12
12
  ``detect_memory_type`` and ``convert_memory``
13
13
  Detection and explicit conversion.
14
14
 
15
+ ``ArrayGeometry``
16
+ Framework-neutral shape inspection for arrays and nominal ``ArrayPayload``
17
+ values. Geometry inspection reads declared shape metadata and does not move
18
+ device data to host memory.
19
+
15
20
  ``memory_types``, ``numpy``, ``cupy``, ``torch``, ``tensorflow``, ``jax``, ``pyclesperanto``
16
21
  Callable memory declarations and wrappers.
17
22
 
@@ -22,7 +22,7 @@ sys.path.insert(0, str(PACKAGE_ROOT / "src"))
22
22
  project = 'arraybridge'
23
23
  copyright = '2025, Tristan Simas'
24
24
  author = 'Tristan Simas'
25
- release = '0.3.0'
25
+ release = '0.3.1'
26
26
 
27
27
  # -- General configuration ---------------------------------------------------
28
28
  # https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
@@ -5,7 +5,7 @@ build-backend = "hatchling.build"
5
5
 
6
6
  [project]
7
7
  name = "arraybridge"
8
- version = "0.3.0"
8
+ version = "0.3.2"
9
9
  description = "Unified API for NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto with automatic memory type conversion"
10
10
  authors = [{name = "Tristan Simas", email = "tristan.simas@mail.mcgill.ca"}]
11
11
  license = {text = "MIT"}
@@ -25,7 +25,11 @@ classifiers = [
25
25
  ]
26
26
  keywords = ["numpy", "cupy", "pytorch", "tensorflow", "jax", "gpu", "array", "tensor", "conversion"]
27
27
 
28
- dependencies = ["numpy>=1.20", "metaclass-registry>=0.1.5"]
28
+ dependencies = [
29
+ "numpy>=1.20",
30
+ "metaclass-registry>=0.1.5",
31
+ "python-introspect>=0.1.11",
32
+ ]
29
33
 
30
34
  [project.optional-dependencies]
31
35
  cupy = ["cupy>=10.0"]
@@ -5,9 +5,10 @@ This package provides automatic memory type conversion, declarative decorators,
5
5
  and unified utilities for working with multiple array/tensor frameworks.
6
6
  """
7
7
 
8
- __version__ = "0.3.0"
8
+ __version__ = "0.3.2"
9
9
 
10
10
  from . import decorators as _decorators
11
+ from .array_geometry import ArrayGeometry
11
12
  from .array_payload import ArrayPayload
12
13
  from .converters import convert_memory, detect_memory_type
13
14
  from .dtype_scaling import SCALING_FUNCTIONS
@@ -39,6 +40,7 @@ __all__ = [
39
40
  "MemoryType",
40
41
  "MemoryContractAttribute",
41
42
  "ArrayPayload",
43
+ "ArrayGeometry",
42
44
  "CPU_MEMORY_TYPES",
43
45
  "GPU_MEMORY_TYPES",
44
46
  "SUPPORTED_MEMORY_TYPES",
@@ -0,0 +1,57 @@
1
+ """Framework-neutral array geometry inspection."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+ from typing import Any
7
+
8
+ import numpy as np
9
+
10
+ from arraybridge.array_payload import ArrayPayload
11
+
12
+
13
+ @dataclass(frozen=True, slots=True)
14
+ class ArrayGeometry:
15
+ """Concrete shape metadata without moving array data between frameworks."""
16
+
17
+ shape: tuple[int, ...]
18
+
19
+ @property
20
+ def ndim(self) -> int:
21
+ """Return the rank derived from the canonical shape."""
22
+
23
+ return len(self.shape)
24
+
25
+ @classmethod
26
+ def from_value(cls, value: Any) -> ArrayGeometry | None:
27
+ """Inspect an array or nominal payload without forcing host conversion."""
28
+
29
+ data = value.array_payload_data() if isinstance(value, ArrayPayload) else value
30
+ declared_shape = getattr(data, "shape", None)
31
+ if declared_shape is not None:
32
+ try:
33
+ return cls(tuple(int(axis_size) for axis_size in declared_shape))
34
+ except (TypeError, ValueError):
35
+ return None
36
+
37
+ try:
38
+ array = np.asarray(data)
39
+ except (TypeError, ValueError):
40
+ return None
41
+ return cls(tuple(int(axis_size) for axis_size in array.shape))
42
+
43
+ @classmethod
44
+ def require_from_value(
45
+ cls,
46
+ value: Any,
47
+ *,
48
+ value_name: str = "Value",
49
+ ) -> ArrayGeometry:
50
+ """Return concrete geometry or reject a value without an array shape."""
51
+
52
+ geometry = cls.from_value(value)
53
+ if geometry is None:
54
+ raise TypeError(
55
+ f"{value_name} requires concrete array geometry, got " f"{type(value).__name__}."
56
+ )
57
+ return geometry
@@ -23,6 +23,7 @@ from typing import Any, ClassVar, TypeVar, cast
23
23
 
24
24
  import numpy as np
25
25
  from metaclass_registry import AutoRegisterMeta, RegistryFamily, RegistryKeyAttribute
26
+ from python_introspect import RuntimeParameterDeclarationABC
26
27
 
27
28
  from arraybridge.array_payload import ArrayPayload
28
29
  from arraybridge.oom_recovery import _execute_with_oom_recovery
@@ -60,7 +61,7 @@ class DtypeConversion(Enum):
60
61
  return dtype_map.get(self, None)
61
62
 
62
63
 
63
- class DtypeConversionConfig(ABC):
64
+ class DtypeConversionConfig(RuntimeParameterDeclarationABC):
64
65
  """Nominal dtype conversion config surface consumed by decorators."""
65
66
 
66
67
  @property
@@ -90,7 +91,7 @@ class DtypeConversionConfig(ABC):
90
91
  )
91
92
 
92
93
 
93
- class SliceBySliceRuntimeParameter:
94
+ class SliceBySliceRuntimeParameter(RuntimeParameterDeclarationABC):
94
95
  """Nominal slice-by-slice execution parameter consumed by decorators."""
95
96
 
96
97
  preserve_for_execution = True
@@ -0,0 +1,53 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ import pytest
5
+
6
+ from arraybridge import ArrayGeometry, ArrayPayload
7
+
8
+
9
+ class DeviceArray:
10
+ """Array-shaped value that rejects implicit host conversion."""
11
+
12
+ shape = (2, 3, 4)
13
+
14
+ def __array__(self, dtype=None):
15
+ del dtype
16
+ raise TypeError("implicit host conversion is forbidden")
17
+
18
+
19
+ class DevicePayload(ArrayPayload):
20
+ def __init__(self, data):
21
+ self.data = data
22
+
23
+ def array_payload_data(self):
24
+ return self.data
25
+
26
+ def with_data(self, data):
27
+ return type(self)(data)
28
+
29
+
30
+ def test_array_geometry_reads_declared_device_shape_without_host_conversion() -> None:
31
+ assert ArrayGeometry.from_value(DeviceArray()) == ArrayGeometry((2, 3, 4))
32
+
33
+
34
+ def test_array_geometry_unwraps_nominal_array_payload() -> None:
35
+ assert ArrayGeometry.from_value(DevicePayload(DeviceArray())) == ArrayGeometry((2, 3, 4))
36
+
37
+
38
+ def test_array_geometry_falls_back_for_python_array_inputs() -> None:
39
+ assert ArrayGeometry.from_value([[1, 2], [3, 4]]) == ArrayGeometry((2, 2))
40
+ assert ArrayGeometry.from_value(np.zeros((4, 5))) == ArrayGeometry((4, 5))
41
+
42
+
43
+ def test_array_geometry_requires_concrete_shape() -> None:
44
+ class UnshapedValue:
45
+ def __array__(self, dtype=None):
46
+ del dtype
47
+ raise TypeError("not an array")
48
+
49
+ with pytest.raises(TypeError, match="Runtime output requires concrete array geometry"):
50
+ ArrayGeometry.require_from_value(
51
+ UnshapedValue(),
52
+ value_name="Runtime output",
53
+ )
@@ -6,6 +6,7 @@ from typing import Any
6
6
 
7
7
  import numpy as np
8
8
  import pytest
9
+ from python_introspect import RuntimeParameterDeclarationABC
9
10
 
10
11
  from arraybridge import ArrayPayload
11
12
  from arraybridge.decorators import (
@@ -33,6 +34,13 @@ class TestDtypeConversion:
33
34
  assert DtypeConversion.UINT8.value == "uint8"
34
35
  assert DtypeConversion.UINT16.value == "uint16"
35
36
  assert DtypeConversion.INT16.value == "int16"
37
+
38
+ def test_runtime_parameters_are_nominal_declarations(self):
39
+ assert issubclass(DtypeConversionConfig, RuntimeParameterDeclarationABC)
40
+ assert issubclass(
41
+ SliceBySliceRuntimeParameter,
42
+ RuntimeParameterDeclarationABC,
43
+ )
36
44
  assert DtypeConversion.INT32.value == "int32"
37
45
  assert DtypeConversion.FLOAT32.value == "float32"
38
46
  assert DtypeConversion.FLOAT64.value == "float64"
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