arraybridge 0.2.11__tar.gz → 0.3.1__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.
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.github/workflows/ci.yml +1 -1
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.github/workflows/coverage-pages.yml +4 -15
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.github/workflows/publish.yml +20 -4
- arraybridge-0.3.1/ADDING_NEW_FRAMEWORKS.md +63 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/CONTRIBUTING.md +36 -21
- {arraybridge-0.2.11 → arraybridge-0.3.1}/PKG-INFO +14 -8
- {arraybridge-0.2.11 → arraybridge-0.3.1}/README.md +10 -7
- arraybridge-0.3.1/TESTING.md +46 -0
- arraybridge-0.3.1/docs/source/advanced_topics.rst +24 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/api_reference.rst +8 -1
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/conf.py +1 -1
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/contributing.rst +3 -3
- arraybridge-0.3.1/docs/source/converters.rst +47 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/decorators.rst +19 -0
- arraybridge-0.3.1/docs/source/gpu_features.rst +34 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/user_guide.rst +4 -4
- {arraybridge-0.2.11 → arraybridge-0.3.1}/pyproject.toml +12 -2
- arraybridge-0.3.1/scripts/release.py +117 -0
- arraybridge-0.3.1/scripts/update_version.py +79 -0
- arraybridge-0.3.1/scripts/verify_release_ready.py +307 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/__init__.py +24 -19
- arraybridge-0.3.1/src/arraybridge/array_geometry.py +57 -0
- arraybridge-0.3.1/src/arraybridge/array_operations.py +396 -0
- arraybridge-0.3.1/src/arraybridge/array_payload.py +31 -0
- arraybridge-0.3.1/src/arraybridge/converters.py +85 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/converters_registry.py +47 -69
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/decorators.py +140 -205
- arraybridge-0.3.1/src/arraybridge/dtype_scaling.py +25 -0
- arraybridge-0.3.1/src/arraybridge/framework_config.py +26 -0
- arraybridge-0.3.1/src/arraybridge/framework_ops.py +7 -0
- arraybridge-0.3.1/src/arraybridge/gpu_cleanup.py +78 -0
- arraybridge-0.3.1/src/arraybridge/oom_recovery.py +90 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/slice_processing.py +36 -5
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/stack_utils.py +23 -127
- arraybridge-0.3.1/src/arraybridge/types.py +984 -0
- arraybridge-0.3.1/src/arraybridge/utils.py +173 -0
- arraybridge-0.3.1/tests/test_array_geometry.py +53 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_converters.py +58 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_converters_registry.py +28 -24
- arraybridge-0.3.1/tests/test_decorators.py +541 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_dtype_scaling.py +85 -59
- arraybridge-0.3.1/tests/test_framework_config.py +29 -0
- arraybridge-0.3.1/tests/test_gpu_cleanup.py +156 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_registry_integration.py +2 -20
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_slice_processing.py +29 -5
- arraybridge-0.3.1/tests/test_stack_utils.py +378 -0
- arraybridge-0.3.1/tests/test_types.py +446 -0
- arraybridge-0.3.1/tests/test_utils.py +248 -0
- arraybridge-0.2.11/.github/badges/coverage.svg +0 -1
- arraybridge-0.2.11/ADDING_NEW_FRAMEWORKS.md +0 -219
- arraybridge-0.2.11/SETUP_INSTRUCTIONS.md +0 -64
- arraybridge-0.2.11/TESTING.md +0 -175
- arraybridge-0.2.11/docs/source/advanced_topics.rst +0 -20
- arraybridge-0.2.11/docs/source/converters.rst +0 -36
- arraybridge-0.2.11/docs/source/gpu_features.rst +0 -19
- arraybridge-0.2.11/scripts/release.py +0 -63
- arraybridge-0.2.11/scripts/update_and_release.py +0 -114
- arraybridge-0.2.11/scripts/update_version.py +0 -111
- arraybridge-0.2.11/scripts/verify_release_ready.py +0 -274
- arraybridge-0.2.11/src/arraybridge/converters.py +0 -71
- arraybridge-0.2.11/src/arraybridge/dtype_scaling.py +0 -179
- arraybridge-0.2.11/src/arraybridge/framework_config.py +0 -442
- arraybridge-0.2.11/src/arraybridge/framework_ops.py +0 -14
- arraybridge-0.2.11/src/arraybridge/gpu_cleanup.py +0 -141
- arraybridge-0.2.11/src/arraybridge/oom_recovery.py +0 -148
- arraybridge-0.2.11/src/arraybridge/types.py +0 -47
- arraybridge-0.2.11/src/arraybridge/utils.py +0 -366
- arraybridge-0.2.11/tests/test_decorators.py +0 -250
- arraybridge-0.2.11/tests/test_framework_config.py +0 -412
- arraybridge-0.2.11/tests/test_gpu_cleanup.py +0 -244
- arraybridge-0.2.11/tests/test_stack_utils.py +0 -169
- arraybridge-0.2.11/tests/test_types.py +0 -71
- arraybridge-0.2.11/tests/test_utils.py +0 -404
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.github/workflows/gpu-tests.yml +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.gitignore +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/.readthedocs.yml +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/LICENSE +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/Makefile +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/CI_ARTIFACT_UPDATE.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/CI_CUPY_FIX.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/CI_IMPROVEMENTS.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/CONFLICT_VISUALIZATION.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/COVERAGE_AUDIT_PLAN.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/DEPLOYMENT_SUMMARY.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/GPU_TESTING_SETUP.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/MERGE_CONFLICT_RESOLUTION.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/MIGRATION_SUMMARY.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/QUICK_FIX_GUIDE.txt +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/README.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/archive/RESOLVED_FILES.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/ci-cd.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/.gitignore +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/Makefile +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/README.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/ci-cd.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/examples/basic_conversion.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/examples/decorators.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/examples/index.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/examples/multi_framework.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/index.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/installation.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/quickstart.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/docs/source/stack_utils.rst +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/paper.bib +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/paper.md +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/src/arraybridge/exceptions.py +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/__init__.py +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/conftest.py +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_exceptions.py +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_integration.py +0 -0
- {arraybridge-0.2.11 → arraybridge-0.3.1}/tests/test_oom_recovery.py +0 -0
|
@@ -6,7 +6,7 @@ on:
|
|
|
6
6
|
workflow_dispatch:
|
|
7
7
|
|
|
8
8
|
permissions:
|
|
9
|
-
contents:
|
|
9
|
+
contents: read
|
|
10
10
|
pages: write
|
|
11
11
|
id-token: write
|
|
12
12
|
|
|
@@ -40,7 +40,6 @@ jobs:
|
|
|
40
40
|
pip install torch --index-url https://download.pytorch.org/whl/cpu
|
|
41
41
|
|
|
42
42
|
- name: Run tests with coverage
|
|
43
|
-
continue-on-error: true # Continue workflow even if tests fail
|
|
44
43
|
run: |
|
|
45
44
|
mkdir -p site
|
|
46
45
|
python -m pytest --cov=arraybridge \
|
|
@@ -50,8 +49,7 @@ jobs:
|
|
|
50
49
|
|
|
51
50
|
- name: Generate coverage badge
|
|
52
51
|
run: |
|
|
53
|
-
|
|
54
|
-
genbadge coverage -i coverage.xml -o .github/badges/coverage.svg -n "coverage"
|
|
52
|
+
genbadge coverage -i coverage.xml -o site/coverage-badge.svg -n "coverage"
|
|
55
53
|
|
|
56
54
|
- name: Create index.html and README
|
|
57
55
|
run: |
|
|
@@ -72,7 +70,7 @@ jobs:
|
|
|
72
70
|
# Create README.md in the site directory
|
|
73
71
|
echo "# arraybridge Code Coverage Reports" > site/README.md
|
|
74
72
|
echo "" >> site/README.md
|
|
75
|
-
echo "This site contains the code coverage reports for the [arraybridge](https://github.com/
|
|
73
|
+
echo "This site contains the code coverage reports for the [arraybridge](https://github.com/OpenHCSDev/arraybridge) project." >> site/README.md
|
|
76
74
|
echo "" >> site/README.md
|
|
77
75
|
echo "## Navigation" >> site/README.md
|
|
78
76
|
echo "" >> site/README.md
|
|
@@ -85,19 +83,10 @@ jobs:
|
|
|
85
83
|
echo "" >> site/README.md
|
|
86
84
|
echo "Last updated: $(date)" >> site/README.md
|
|
87
85
|
|
|
88
|
-
- name: Commit and push if coverage badge changed
|
|
89
|
-
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
90
|
-
run: |
|
|
91
|
-
git config --local user.email "github-actions[bot]@users.noreply.github.com"
|
|
92
|
-
git config --local user.name "github-actions[bot]"
|
|
93
|
-
git add .github/badges/coverage.svg -f
|
|
94
|
-
git commit -m "chore: update coverage badge" || exit 0
|
|
95
|
-
git push
|
|
96
|
-
|
|
97
86
|
- name: Check GitHub Pages status
|
|
98
87
|
run: |
|
|
99
88
|
echo "⚠️ IMPORTANT: Make sure GitHub Pages is enabled in your repository settings!"
|
|
100
|
-
echo "Go to https://github.com/
|
|
89
|
+
echo "Go to https://github.com/OpenHCSDev/arraybridge/settings/pages"
|
|
101
90
|
echo "Set 'Source' to 'GitHub Actions' to enable GitHub Pages deployment."
|
|
102
91
|
|
|
103
92
|
- name: Setup Pages
|
|
@@ -20,6 +20,8 @@ jobs:
|
|
|
20
20
|
steps:
|
|
21
21
|
- name: Checkout code
|
|
22
22
|
uses: actions/checkout@v4
|
|
23
|
+
with:
|
|
24
|
+
fetch-depth: 0
|
|
23
25
|
|
|
24
26
|
- name: Set up Python
|
|
25
27
|
uses: actions/setup-python@v5
|
|
@@ -29,7 +31,21 @@ jobs:
|
|
|
29
31
|
- name: Install build dependencies
|
|
30
32
|
run: |
|
|
31
33
|
python -m pip install --upgrade pip
|
|
32
|
-
pip install
|
|
34
|
+
pip install -e ".[dev]"
|
|
35
|
+
|
|
36
|
+
- name: Validate source and tests
|
|
37
|
+
run: |
|
|
38
|
+
ruff check src/ scripts/
|
|
39
|
+
black --check src/ scripts/
|
|
40
|
+
mypy src/
|
|
41
|
+
pytest -q --no-cov
|
|
42
|
+
|
|
43
|
+
- name: Verify release tag and main ancestry
|
|
44
|
+
run: |
|
|
45
|
+
declared_version=$(python -c 'import tomllib; print(tomllib.load(open("pyproject.toml", "rb"))["project"]["version"])')
|
|
46
|
+
test "$GITHUB_REF_NAME" = "v$declared_version"
|
|
47
|
+
git fetch origin main
|
|
48
|
+
git merge-base --is-ancestor "$GITHUB_SHA" origin/main
|
|
33
49
|
|
|
34
50
|
- name: Build package
|
|
35
51
|
run: python -m build
|
|
@@ -39,6 +55,9 @@ jobs:
|
|
|
39
55
|
pip install twine
|
|
40
56
|
twine check dist/*
|
|
41
57
|
|
|
58
|
+
- name: Publish to PyPI
|
|
59
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
60
|
+
|
|
42
61
|
- name: Create GitHub Release
|
|
43
62
|
uses: softprops/action-gh-release@v2
|
|
44
63
|
with:
|
|
@@ -46,6 +65,3 @@ jobs:
|
|
|
46
65
|
generate_release_notes: true
|
|
47
66
|
env:
|
|
48
67
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
49
|
-
|
|
50
|
-
- name: Publish to PyPI
|
|
51
|
-
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Adding a framework
|
|
2
|
+
|
|
3
|
+
This is a maintainer how-to for extending ArrayBridge's closed framework
|
|
4
|
+
taxonomy. Applications should consume `MemoryType`; they should not add their
|
|
5
|
+
own framework registry.
|
|
6
|
+
|
|
7
|
+
## 1. Define typed leaves
|
|
8
|
+
|
|
9
|
+
Add an `ArrayOperations` bundle in
|
|
10
|
+
`src/arraybridge/array_operations.py`. It must provide four ordinary callables:
|
|
11
|
+
|
|
12
|
+
- project an array to NumPy;
|
|
13
|
+
- create an array from NumPy on the requested framework-local device;
|
|
14
|
+
- stack prepared 2D arrays into one 3D array;
|
|
15
|
+
- apply the framework's dtype-scaling semantics.
|
|
16
|
+
|
|
17
|
+
Define device, stream, DLPack, cleanup, and OOM leaves in
|
|
18
|
+
`src/arraybridge/types.py`. Use the no-op defaults in `FrameworkRuntime` only
|
|
19
|
+
when the framework genuinely lacks that capability. Do not encode behavior as
|
|
20
|
+
strings or add a parallel `MemoryType`-keyed table.
|
|
21
|
+
|
|
22
|
+
## 2. Add the declaration
|
|
23
|
+
|
|
24
|
+
Add one `MemoryType` member carrying:
|
|
25
|
+
|
|
26
|
+
1. its stable value and import name;
|
|
27
|
+
2. its display name and module aliases;
|
|
28
|
+
3. whether it is GPU-backed;
|
|
29
|
+
4. any environment defaults that must be set before first import;
|
|
30
|
+
5. its `FrameworkRuntime` leaves;
|
|
31
|
+
6. its `ArrayOperations` bundle.
|
|
32
|
+
|
|
33
|
+
The converter classes, target conversion methods, compatibility operation view,
|
|
34
|
+
dtype-scaling view, cleanup adapters, and framework decorator are generated
|
|
35
|
+
from the enum. Do not wire them manually.
|
|
36
|
+
|
|
37
|
+
## 3. Prove the extension
|
|
38
|
+
|
|
39
|
+
Add focused tests for:
|
|
40
|
+
|
|
41
|
+
- module-name detection and optional-dependency failure;
|
|
42
|
+
- NumPy round trips and every supported DLPack pair;
|
|
43
|
+
- CPU-only installations of a nominally GPU framework;
|
|
44
|
+
- invalid, negative, and multiple framework-local device IDs;
|
|
45
|
+
- same-framework moves between two devices;
|
|
46
|
+
- one-, two-, and multi-slice stack/unstack behavior;
|
|
47
|
+
- immutable array types;
|
|
48
|
+
- cleanup and OOM behavior without importing an absent framework;
|
|
49
|
+
- generated registry and export completeness.
|
|
50
|
+
|
|
51
|
+
Run:
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
ruff check src tests
|
|
55
|
+
black --check src tests
|
|
56
|
+
mypy src --ignore-missing-imports
|
|
57
|
+
pytest
|
|
58
|
+
python -m sphinx -E -W --keep-going -b html docs/source /tmp/arraybridge-docs
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When GPU hardware is available, also exercise every installed framework pair in
|
|
62
|
+
one process. This catches import-order, allocator-coexistence, DLPack, and real
|
|
63
|
+
API-shape defects that isolated mocks cannot prove.
|
|
@@ -332,35 +332,48 @@ git push origin feature/your-feature-name
|
|
|
332
332
|
|
|
333
333
|
### 1. Update Version
|
|
334
334
|
|
|
335
|
-
|
|
335
|
+
Update all three validated version projections with the side-effect-free helper:
|
|
336
336
|
|
|
337
|
-
```
|
|
338
|
-
|
|
339
|
-
version = "0.2.0"
|
|
337
|
+
```bash
|
|
338
|
+
python scripts/update_version.py 0.3.0
|
|
340
339
|
```
|
|
341
340
|
|
|
341
|
+
Review the package, project, and documentation changes, then run
|
|
342
|
+
`python scripts/verify_release_ready.py --allow-dirty` before committing.
|
|
343
|
+
|
|
342
344
|
### 2. Update Changelog
|
|
343
345
|
|
|
344
346
|
Add release notes to `CHANGELOG.md` (if exists) or create GitHub release notes.
|
|
345
347
|
|
|
346
|
-
### 3.
|
|
348
|
+
### 3. Validate, Commit, and Push
|
|
347
349
|
|
|
348
350
|
```bash
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
351
|
+
ruff check src tests scripts
|
|
352
|
+
black --check src scripts
|
|
353
|
+
mypy src --ignore-missing-imports
|
|
354
|
+
pytest
|
|
355
|
+
python -m sphinx -E -W --keep-going -b html docs/source /tmp/arraybridge-docs
|
|
356
|
+
git commit
|
|
357
|
+
git push origin HEAD:main
|
|
358
|
+
```
|
|
352
359
|
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
360
|
+
### 4. Create the Release Tag
|
|
361
|
+
|
|
362
|
+
After the pushed commit is exactly `origin/main`, run:
|
|
363
|
+
|
|
364
|
+
```bash
|
|
365
|
+
python scripts/release.py
|
|
356
366
|
```
|
|
357
367
|
|
|
358
|
-
|
|
368
|
+
The script validates the clean published commit, confirms the PyPI version, and
|
|
369
|
+
pushes the matching annotated tag.
|
|
370
|
+
|
|
371
|
+
### 5. Automated Publishing
|
|
359
372
|
|
|
360
373
|
GitHub Actions will automatically:
|
|
361
|
-
1.
|
|
362
|
-
2.
|
|
363
|
-
3.
|
|
374
|
+
1. verify the tag, source, tests, and package metadata;
|
|
375
|
+
2. publish to PyPI;
|
|
376
|
+
3. create the GitHub release.
|
|
364
377
|
|
|
365
378
|
## Development Guidelines
|
|
366
379
|
|
|
@@ -391,12 +404,14 @@ GitHub Actions will automatically:
|
|
|
391
404
|
|
|
392
405
|
To add support for a new framework:
|
|
393
406
|
|
|
394
|
-
1.
|
|
395
|
-
2. Add
|
|
396
|
-
3.
|
|
397
|
-
4.
|
|
398
|
-
|
|
399
|
-
|
|
407
|
+
1. Add typed array-operation leaves in `array_operations.py`.
|
|
408
|
+
2. Add one `MemoryType` declaration carrying those operations and its runtime leaves.
|
|
409
|
+
3. Add detection, conversion-pair, stack, cross-device, and optional-dependency tests.
|
|
410
|
+
4. Update the extension and reference documentation.
|
|
411
|
+
|
|
412
|
+
Do not add framework behavior to `_FRAMEWORK_CONFIG`, a consumer registry, or
|
|
413
|
+
generated decorator exports. See `ADDING_NEW_FRAMEWORKS.md` for the complete
|
|
414
|
+
declaration-owned extension procedure.
|
|
400
415
|
|
|
401
416
|
## Getting Help
|
|
402
417
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: arraybridge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.3.1
|
|
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
|
|
@@ -34,10 +34,13 @@ Provides-Extra: cupy
|
|
|
34
34
|
Requires-Dist: cupy>=10.0; extra == 'cupy'
|
|
35
35
|
Provides-Extra: dev
|
|
36
36
|
Requires-Dist: black>=23.0; extra == 'dev'
|
|
37
|
+
Requires-Dist: build>=1.0; extra == 'dev'
|
|
37
38
|
Requires-Dist: mypy>=1.0; extra == 'dev'
|
|
39
|
+
Requires-Dist: packaging>=23.0; extra == 'dev'
|
|
38
40
|
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
39
41
|
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
40
42
|
Requires-Dist: ruff>=0.1.0; extra == 'dev'
|
|
43
|
+
Requires-Dist: twine>=5.0; extra == 'dev'
|
|
41
44
|
Provides-Extra: docs
|
|
42
45
|
Requires-Dist: sphinx-autodoc-typehints>=1.25; extra == 'docs'
|
|
43
46
|
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
|
|
@@ -92,8 +95,10 @@ copy = convert_memory(
|
|
|
92
95
|
```
|
|
93
96
|
|
|
94
97
|
`convert_memory` requires the declared source type, target type, and device id.
|
|
95
|
-
|
|
96
|
-
required even for CPU conversions so call sites have one
|
|
98
|
+
The source and target `MemoryType` declarations perform conversion directly.
|
|
99
|
+
The device id is required even for CPU conversions so call sites have one
|
|
100
|
+
stable signature. A GPU target must declare that identifier as available;
|
|
101
|
+
ArrayBridge does not silently place the value on the CPU.
|
|
97
102
|
|
|
98
103
|
## Declarative decorators
|
|
99
104
|
|
|
@@ -105,11 +110,12 @@ def normalize(image):
|
|
|
105
110
|
return image / max(float(image.max()), 1.0)
|
|
106
111
|
```
|
|
107
112
|
|
|
108
|
-
The framework decorators attach `input_memory_type` and
|
|
109
|
-
metadata, provide dtype/slice runtime parameters, and
|
|
110
|
-
stream/OOM handling where supported. They do **not**
|
|
111
|
-
between frameworks and do not accept a `gpu_id`
|
|
112
|
-
call `convert_memory` at the boundary it plans
|
|
113
|
+
The framework decorators attach `input_memory_type`, `output_memory_type`, and
|
|
114
|
+
`execution_memory_type` metadata, provide dtype/slice runtime parameters, and
|
|
115
|
+
add framework-specific stream/OOM handling where supported. They do **not**
|
|
116
|
+
convert inputs or outputs between frameworks and do not accept a `gpu_id`
|
|
117
|
+
argument. A host runtime must call `convert_memory` at the boundary it plans and
|
|
118
|
+
scope execution using the execution declaration.
|
|
113
119
|
|
|
114
120
|
## Stack utilities
|
|
115
121
|
|
|
@@ -25,8 +25,10 @@ copy = convert_memory(
|
|
|
25
25
|
```
|
|
26
26
|
|
|
27
27
|
`convert_memory` requires the declared source type, target type, and device id.
|
|
28
|
-
|
|
29
|
-
required even for CPU conversions so call sites have one
|
|
28
|
+
The source and target `MemoryType` declarations perform conversion directly.
|
|
29
|
+
The device id is required even for CPU conversions so call sites have one
|
|
30
|
+
stable signature. A GPU target must declare that identifier as available;
|
|
31
|
+
ArrayBridge does not silently place the value on the CPU.
|
|
30
32
|
|
|
31
33
|
## Declarative decorators
|
|
32
34
|
|
|
@@ -38,11 +40,12 @@ def normalize(image):
|
|
|
38
40
|
return image / max(float(image.max()), 1.0)
|
|
39
41
|
```
|
|
40
42
|
|
|
41
|
-
The framework decorators attach `input_memory_type` and
|
|
42
|
-
metadata, provide dtype/slice runtime parameters, and
|
|
43
|
-
stream/OOM handling where supported. They do **not**
|
|
44
|
-
between frameworks and do not accept a `gpu_id`
|
|
45
|
-
call `convert_memory` at the boundary it plans
|
|
43
|
+
The framework decorators attach `input_memory_type`, `output_memory_type`, and
|
|
44
|
+
`execution_memory_type` metadata, provide dtype/slice runtime parameters, and
|
|
45
|
+
add framework-specific stream/OOM handling where supported. They do **not**
|
|
46
|
+
convert inputs or outputs between frameworks and do not accept a `gpu_id`
|
|
47
|
+
argument. A host runtime must call `convert_memory` at the boundary it plans and
|
|
48
|
+
scope execution using the execution declaration.
|
|
46
49
|
|
|
47
50
|
## Stack utilities
|
|
48
51
|
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
# Testing ArrayBridge
|
|
2
|
+
|
|
3
|
+
This is the practical test guide. The workflow files under `.github/workflows`
|
|
4
|
+
are the authority for the current CI matrix.
|
|
5
|
+
|
|
6
|
+
## Local core checks
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
python -m pip install -e ".[dev,docs]"
|
|
10
|
+
ruff check src tests
|
|
11
|
+
black --check src tests
|
|
12
|
+
mypy src --ignore-missing-imports
|
|
13
|
+
pytest
|
|
14
|
+
python -m sphinx -E -W --keep-going -b html docs/source /tmp/arraybridge-docs
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
The default suite uses real optional frameworks when installed and otherwise
|
|
18
|
+
exercises declared unavailable paths and focused fakes. Markers such as
|
|
19
|
+
`torch`, `tensorflow`, `jax`, `cupy`, `pyclesperanto`, and `gpu` can select or
|
|
20
|
+
exclude framework-specific tests.
|
|
21
|
+
|
|
22
|
+
## Real GPU lattice check
|
|
23
|
+
|
|
24
|
+
On a GPU host, validate more than a single NumPy round trip:
|
|
25
|
+
|
|
26
|
+
- import all installed frameworks in one fresh process;
|
|
27
|
+
- enumerate framework-local devices through each `MemoryType`;
|
|
28
|
+
- convert a small exact array through every available source-target pair;
|
|
29
|
+
- stack and unstack one, two, and several planes in every framework;
|
|
30
|
+
- verify same-framework movement across multiple local devices when present;
|
|
31
|
+
- confirm absent frameworks are not imported by discovery or cleanup;
|
|
32
|
+
- exercise DLPack success and explicit CPU fallback paths;
|
|
33
|
+
- target OOM cleanup to the device that owned execution.
|
|
34
|
+
|
|
35
|
+
Use a fresh process and unset TensorFlow/JAX allocator variables when checking
|
|
36
|
+
that declaration-owned import defaults work. Framework warnings about shared
|
|
37
|
+
CUDA plugin registration should be recorded separately from value, device, or
|
|
38
|
+
shape failures.
|
|
39
|
+
|
|
40
|
+
## Interpreting CI
|
|
41
|
+
|
|
42
|
+
The main CI workflow runs the test suite across its declared Python and OS
|
|
43
|
+
matrix. The manual GPU-named workflow installs CPU-capable Torch and JAX on a
|
|
44
|
+
standard runner; it does not prove CUDA behavior. Real multi-framework and
|
|
45
|
+
multi-device results therefore remain a required release check on suitable
|
|
46
|
+
hardware.
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Advanced extension topics
|
|
2
|
+
=========================
|
|
3
|
+
|
|
4
|
+
Framework behavior is carried by each ``MemoryType`` member. Add a framework by
|
|
5
|
+
extending that owning declaration:
|
|
6
|
+
|
|
7
|
+
1. add the ``MemoryType`` member;
|
|
8
|
+
2. provide its typed runtime and array-operation leaves;
|
|
9
|
+
3. define conversion, stack, scaling, and device behavior;
|
|
10
|
+
4. add cleanup and OOM behavior only when the framework supports them;
|
|
11
|
+
5. exercise detection and every supported conversion pair.
|
|
12
|
+
|
|
13
|
+
Do not add a parallel framework-name table in a consumer. Generic consumers use
|
|
14
|
+
``MemoryType`` directly. The converter registry and historical framework config
|
|
15
|
+
are generated projections, not authorities.
|
|
16
|
+
|
|
17
|
+
Version 0.3 keeps the private ``_FRAMEWORK_CONFIG`` and ``_FRAMEWORK_OPS`` names
|
|
18
|
+
only as read-only operation views. Their historical mapping shape is not a
|
|
19
|
+
compatibility contract. Migrate callers to ``MemoryType`` methods.
|
|
20
|
+
|
|
21
|
+
Conversion caching and batching belong to the caller because value lifetime and
|
|
22
|
+
semantic identity are application concerns. ArrayBridge functions remain
|
|
23
|
+
stateless at the conversion boundary except for declared thread-local GPU
|
|
24
|
+
context.
|
|
@@ -5,11 +5,18 @@ Public imports
|
|
|
5
5
|
--------------
|
|
6
6
|
|
|
7
7
|
``MemoryType``, ``CPU_MEMORY_TYPES``, ``GPU_MEMORY_TYPES``, ``SUPPORTED_MEMORY_TYPES``
|
|
8
|
-
|
|
8
|
+
Framework declarations. Each member owns import identity, conversion,
|
|
9
|
+
stacking, dtype scaling, device discovery, scoped selection, movement,
|
|
10
|
+
DLPack import/export, cleanup, and pre-import coexistence defaults.
|
|
9
11
|
|
|
10
12
|
``detect_memory_type`` and ``convert_memory``
|
|
11
13
|
Detection and explicit conversion.
|
|
12
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
|
+
|
|
13
20
|
``memory_types``, ``numpy``, ``cupy``, ``torch``, ``tensorflow``, ``jax``, ``pyclesperanto``
|
|
14
21
|
Callable memory declarations and wrappers.
|
|
15
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.
|
|
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
|
|
@@ -17,9 +17,9 @@ Framework extensions
|
|
|
17
17
|
--------------------
|
|
18
18
|
|
|
19
19
|
A framework extension must update the nominal ``MemoryType`` declaration and
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
its typed operation leaves. Add detection, conversion-pair, stack,
|
|
21
|
+
cross-device, and optional-dependency tests. Consumers should not maintain a
|
|
22
|
+
second framework-name registry.
|
|
23
23
|
|
|
24
24
|
See :doc:`advanced_topics` for the ownership model and the repository's
|
|
25
25
|
`contribution guide
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
Conversion system
|
|
2
|
+
=================
|
|
3
|
+
|
|
4
|
+
``convert_memory(data, source_type, target_type, gpu_id)`` resolves the source
|
|
5
|
+
and target ``MemoryType`` declarations and lets those declarations perform the
|
|
6
|
+
conversion.
|
|
7
|
+
|
|
8
|
+
.. code-block:: python
|
|
9
|
+
|
|
10
|
+
import numpy as np
|
|
11
|
+
|
|
12
|
+
from arraybridge import MemoryType, convert_memory
|
|
13
|
+
|
|
14
|
+
value = np.arange(4)
|
|
15
|
+
result = convert_memory(
|
|
16
|
+
value,
|
|
17
|
+
MemoryType.NUMPY,
|
|
18
|
+
MemoryType.NUMPY,
|
|
19
|
+
0,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
Both ``source_type`` and ``target_type`` accept either the canonical
|
|
23
|
+
``MemoryType`` member or its string value. Decorators normalize the same
|
|
24
|
+
members to string metadata at declaration time, so callable contracts and
|
|
25
|
+
conversion plans share one taxonomy without carrying duplicate enum classes.
|
|
26
|
+
|
|
27
|
+
Call ``detect_memory_type`` when the source type is not already known. Passing a
|
|
28
|
+
wrong source declaration is a caller error; conversion planning should keep the
|
|
29
|
+
declared type aligned with the actual value.
|
|
30
|
+
|
|
31
|
+
Device semantics
|
|
32
|
+
----------------
|
|
33
|
+
|
|
34
|
+
``gpu_id`` is required. GPU converters use it for allocation or device
|
|
35
|
+
selection. CPU conversion accepts the same argument for a uniform API. Moving a
|
|
36
|
+
value between two devices is expressed as conversion with the target device id.
|
|
37
|
+
|
|
38
|
+
Declarations prefer framework-native or DLPack paths when both endpoints
|
|
39
|
+
support them and otherwise use an explicit NumPy round trip. No zero-copy
|
|
40
|
+
guarantee applies to every pair.
|
|
41
|
+
|
|
42
|
+
Failures
|
|
43
|
+
--------
|
|
44
|
+
|
|
45
|
+
Invalid framework names raise ``ValueError``. Conversion failures raise
|
|
46
|
+
``MemoryConversionError`` with source/target context. Optional frameworks are
|
|
47
|
+
loaded only when their declaration is used.
|
|
@@ -27,6 +27,21 @@ metadata, add keyword-only ``slice_by_slice`` and ``dtype_config`` runtime
|
|
|
27
27
|
parameters, apply the selected dtype policy, and wrap supported GPU frameworks
|
|
28
28
|
with thread-local stream/OOM handling.
|
|
29
29
|
|
|
30
|
+
Framework helpers also attach ``execution_memory_type``. It identifies the
|
|
31
|
+
framework that owns the function body even when ``input_type`` or
|
|
32
|
+
``output_type`` is overridden. Host runtimes use that declaration when scoping
|
|
33
|
+
callable execution; boundary types alone do not prove execution ownership.
|
|
34
|
+
|
|
35
|
+
Metadata key API
|
|
36
|
+
----------------
|
|
37
|
+
|
|
38
|
+
``MemoryContractAttribute`` is the public owner of the callable metadata keys:
|
|
39
|
+
``INPUT`` maps to ``input_memory_type``, ``OUTPUT`` maps to
|
|
40
|
+
``output_memory_type``, and ``EXECUTION`` maps to ``execution_memory_type``.
|
|
41
|
+
Each member provides ``read(namespace, default=None)`` and
|
|
42
|
+
``write(namespace, value)`` for object and mapping namespaces. Host libraries
|
|
43
|
+
can consume these members without maintaining a duplicate key registry.
|
|
44
|
+
|
|
30
45
|
The decorator does not accept ``gpu_id`` or ``clear_cuda_cache``. Device
|
|
31
46
|
selection belongs to explicit conversion or the host runtime. A non-callable
|
|
32
47
|
``contract`` is stored as declarative metadata; a callable contract validates
|
|
@@ -38,3 +53,7 @@ Dtype policy
|
|
|
38
53
|
Direct calls default to preserving the input dtype. Hosts can pass an object
|
|
39
54
|
implementing ``DtypeConversionConfig`` to select native or explicit output dtype
|
|
40
55
|
behavior.
|
|
56
|
+
|
|
57
|
+
``wrap_dtype_preserving_callable(func, memory_type)`` exposes the dtype and
|
|
58
|
+
slice-control wrapper as a public integration boundary for host registries that
|
|
59
|
+
already own their memory and processing contracts.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
GPU lifecycle
|
|
2
|
+
=============
|
|
3
|
+
|
|
4
|
+
GPU-backed conversion uses the explicit ``gpu_id`` passed to
|
|
5
|
+
``convert_memory``, ``stack_slices``, or ``unstack_slices``. Framework-specific
|
|
6
|
+
``MemoryType`` declarations own device discovery, validation, scopes, movement,
|
|
7
|
+
and cache cleanup. Device identifiers are local to one framework. Equal numeric
|
|
8
|
+
identifiers from different frameworks do not establish physical-device
|
|
9
|
+
identity.
|
|
10
|
+
|
|
11
|
+
Before importing TensorFlow or JAX, their declarations apply coexistence-safe
|
|
12
|
+
defaults with ``setdefault``: TensorFlow memory growth is enabled and JAX GPU
|
|
13
|
+
preallocation is disabled. An environment value supplied by the host is never
|
|
14
|
+
overwritten. Hosts that import optional frameworks themselves should call
|
|
15
|
+
``MemoryType.prepare_import()`` first. ArrayBridge warns when it encounters an
|
|
16
|
+
already-loaded framework whose import-time defaults were absent.
|
|
17
|
+
|
|
18
|
+
JAX float64 output requires x64 mode to be enabled before import. ArrayBridge
|
|
19
|
+
raises instead of silently returning float32 when a caller requests float64
|
|
20
|
+
while that capability is disabled.
|
|
21
|
+
|
|
22
|
+
Decorated GPU callables may execute in a thread-local framework stream and may
|
|
23
|
+
retry supported OOM failures when ``oom_recovery=True``. Decorators do not
|
|
24
|
+
select a device and do not convert an incompatible input.
|
|
25
|
+
|
|
26
|
+
``cleanup_all_gpu_frameworks(device_id=None)`` invokes allocator cleanup only
|
|
27
|
+
for loaded frameworks that declare a real cleanup leaf. Supplying ``device_id``
|
|
28
|
+
targets that framework-local identifier. Cleanup never imports an absent
|
|
29
|
+
framework. JAX compilation-cache clearing is not presented as GPU-memory
|
|
30
|
+
cleanup. The application decides when values are no longer live and cleanup is
|
|
31
|
+
appropriate.
|
|
32
|
+
|
|
33
|
+
ArrayBridge exposes mechanisms, not scheduling policy. Worker counts, device
|
|
34
|
+
assignment, retry scope, and concurrency limits belong to the host runtime.
|
|
@@ -26,10 +26,10 @@ Framework names
|
|
|
26
26
|
|
|
27
27
|
The public conversion and stack APIs use string values: ``numpy``, ``cupy``,
|
|
28
28
|
``torch``, ``tensorflow``, ``jax``, and ``pyclesperanto``. ``convert_memory``
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
29
|
+
accepts the canonical ``MemoryType`` member at both its source and target
|
|
30
|
+
boundaries. Availability depends on optional dependencies and hardware.
|
|
31
|
+
ArrayBridge never silently substitutes a different framework for an invalid
|
|
32
|
+
target.
|
|
33
33
|
|
|
34
34
|
Applications should carry these values through typed configuration or plans,
|
|
35
35
|
not infer them from function names.
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
[build-system]
|
|
2
|
-
|
|
2
|
+
# Hatchling 1.32 emits Core Metadata 2.5, which Twine 6.2 rejects.
|
|
3
|
+
requires = ["hatchling>=1.28,<1.32"]
|
|
3
4
|
build-backend = "hatchling.build"
|
|
4
5
|
|
|
5
6
|
[project]
|
|
6
7
|
name = "arraybridge"
|
|
7
|
-
version = "0.
|
|
8
|
+
version = "0.3.1"
|
|
8
9
|
description = "Unified API for NumPy, CuPy, PyTorch, TensorFlow, JAX, and pyclesperanto with automatic memory type conversion"
|
|
9
10
|
authors = [{name = "Tristan Simas", email = "tristan.simas@mail.mcgill.ca"}]
|
|
10
11
|
license = {text = "MIT"}
|
|
@@ -71,6 +72,9 @@ all = [
|
|
|
71
72
|
dev = [
|
|
72
73
|
"pytest>=7.0",
|
|
73
74
|
"pytest-cov>=4.0",
|
|
75
|
+
"build>=1.0",
|
|
76
|
+
"twine>=5.0",
|
|
77
|
+
"packaging>=23.0",
|
|
74
78
|
"black>=23.0",
|
|
75
79
|
"ruff>=0.1.0",
|
|
76
80
|
"mypy>=1.0",
|
|
@@ -119,6 +123,12 @@ select = ["E", "F", "I", "N", "W", "UP"]
|
|
|
119
123
|
|
|
120
124
|
[tool.mypy]
|
|
121
125
|
python_version = "3.10"
|
|
126
|
+
follow_imports_for_stubs = true
|
|
127
|
+
ignore_missing_imports = true
|
|
122
128
|
warn_return_any = true
|
|
123
129
|
warn_unused_configs = true
|
|
124
130
|
disallow_untyped_defs = false # Too strict for scientific code
|
|
131
|
+
|
|
132
|
+
[[tool.mypy.overrides]]
|
|
133
|
+
module = "numpy.*"
|
|
134
|
+
follow_imports = "skip"
|