arraybridge 0.2.0__tar.gz → 0.2.9__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 (96) hide show
  1. arraybridge-0.2.9/.github/badges/coverage.svg +1 -0
  2. arraybridge-0.2.9/.github/workflows/ci.yml +158 -0
  3. arraybridge-0.2.9/.github/workflows/coverage-pages.yml +115 -0
  4. arraybridge-0.2.9/.github/workflows/gpu-tests.yml +79 -0
  5. arraybridge-0.2.9/ADDING_NEW_FRAMEWORKS.md +215 -0
  6. arraybridge-0.2.9/CI_ARTIFACT_UPDATE.md +47 -0
  7. arraybridge-0.2.9/CI_CUPY_FIX.md +104 -0
  8. arraybridge-0.2.9/COVERAGE_AUDIT_PLAN.md +410 -0
  9. arraybridge-0.2.9/DEPLOYMENT_SUMMARY.md +62 -0
  10. arraybridge-0.2.9/GPU_TESTING_SETUP.md +165 -0
  11. arraybridge-0.2.9/MIGRATION_SUMMARY.md +193 -0
  12. {arraybridge-0.2.0 → arraybridge-0.2.9}/PKG-INFO +20 -5
  13. {arraybridge-0.2.0 → arraybridge-0.2.9}/README.md +3 -1
  14. arraybridge-0.2.9/SETUP_INSTRUCTIONS.md +64 -0
  15. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/stack_utils.rst +43 -40
  16. arraybridge-0.2.9/paper.bib +76 -0
  17. arraybridge-0.2.9/paper.md +149 -0
  18. {arraybridge-0.2.0 → arraybridge-0.2.9}/pyproject.toml +37 -7
  19. arraybridge-0.2.9/scripts/release.py +63 -0
  20. arraybridge-0.2.9/scripts/update_and_release.py +114 -0
  21. arraybridge-0.2.9/scripts/update_version.py +111 -0
  22. arraybridge-0.2.9/scripts/verify_release_ready.py +274 -0
  23. arraybridge-0.2.9/src/arraybridge/__init__.py +70 -0
  24. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/converters.py +17 -7
  25. arraybridge-0.2.9/src/arraybridge/converters_registry.py +196 -0
  26. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/decorators.py +91 -101
  27. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/dtype_scaling.py +52 -30
  28. arraybridge-0.2.9/src/arraybridge/framework_config.py +442 -0
  29. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/framework_ops.py +0 -1
  30. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/gpu_cleanup.py +20 -28
  31. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/oom_recovery.py +8 -8
  32. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/slice_processing.py +7 -3
  33. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/stack_utils.py +28 -31
  34. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/types.py +2 -25
  35. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/utils.py +44 -30
  36. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/conftest.py +46 -5
  37. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/test_converters.py +7 -5
  38. arraybridge-0.2.9/tests/test_converters_registry.py +149 -0
  39. arraybridge-0.2.9/tests/test_decorators.py +234 -0
  40. arraybridge-0.2.9/tests/test_dtype_scaling.py +331 -0
  41. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/test_exceptions.py +5 -7
  42. arraybridge-0.2.9/tests/test_framework_config.py +412 -0
  43. arraybridge-0.2.9/tests/test_gpu_cleanup.py +244 -0
  44. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/test_integration.py +8 -6
  45. arraybridge-0.2.9/tests/test_oom_recovery.py +141 -0
  46. arraybridge-0.2.9/tests/test_registry_integration.py +131 -0
  47. arraybridge-0.2.9/tests/test_slice_processing.py +121 -0
  48. arraybridge-0.2.9/tests/test_stack_utils.py +169 -0
  49. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/test_types.py +2 -1
  50. arraybridge-0.2.9/tests/test_utils.py +404 -0
  51. arraybridge-0.2.0/.github/workflows/ci.yml +0 -153
  52. arraybridge-0.2.0/.github/workflows/gpu-tests.yml +0 -69
  53. arraybridge-0.2.0/src/arraybridge/__init__.py +0 -37
  54. arraybridge-0.2.0/src/arraybridge/conversion_helpers.py +0 -150
  55. arraybridge-0.2.0/src/arraybridge/framework_config.py +0 -459
  56. arraybridge-0.2.0/tests/test_utils.py +0 -151
  57. {arraybridge-0.2.0 → arraybridge-0.2.9}/.github/workflows/publish.yml +0 -0
  58. {arraybridge-0.2.0 → arraybridge-0.2.9}/.gitignore +0 -0
  59. {arraybridge-0.2.0 → arraybridge-0.2.9}/.readthedocs.yml +0 -0
  60. {arraybridge-0.2.0 → arraybridge-0.2.9}/CI_IMPROVEMENTS.md +0 -0
  61. {arraybridge-0.2.0 → arraybridge-0.2.9}/CONFLICT_VISUALIZATION.md +0 -0
  62. {arraybridge-0.2.0 → arraybridge-0.2.9}/CONTRIBUTING.md +0 -0
  63. {arraybridge-0.2.0 → arraybridge-0.2.9}/LICENSE +0 -0
  64. {arraybridge-0.2.0 → arraybridge-0.2.9}/MERGE_CONFLICT_RESOLUTION.md +0 -0
  65. {arraybridge-0.2.0 → arraybridge-0.2.9}/QUICK_FIX_GUIDE.txt +0 -0
  66. {arraybridge-0.2.0 → arraybridge-0.2.9}/RESOLVED_FILES.md +0 -0
  67. {arraybridge-0.2.0 → arraybridge-0.2.9}/TESTING.md +0 -0
  68. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/Makefile +0 -0
  69. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/ci-cd.md +0 -0
  70. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/.gitignore +0 -0
  71. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/Makefile +0 -0
  72. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/README.md +0 -0
  73. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/advanced_topics.rst +0 -0
  74. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/converters.rst +0 -0
  75. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/decorators.rst +0 -0
  76. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/exceptions.rst +0 -0
  77. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/index.rst +0 -0
  78. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/types.rst +0 -0
  79. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api/utils.rst +0 -0
  80. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/api_reference.rst +0 -0
  81. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/ci-cd.rst +0 -0
  82. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/conf.py +0 -0
  83. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/contributing.rst +0 -0
  84. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/converters.rst +0 -0
  85. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/decorators.rst +0 -0
  86. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/examples/basic_conversion.rst +0 -0
  87. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/examples/decorators.rst +0 -0
  88. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/examples/index.rst +0 -0
  89. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/examples/multi_framework.rst +0 -0
  90. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/gpu_features.rst +0 -0
  91. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/index.rst +0 -0
  92. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/installation.rst +0 -0
  93. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/quickstart.rst +0 -0
  94. {arraybridge-0.2.0 → arraybridge-0.2.9}/docs/source/user_guide.rst +0 -0
  95. {arraybridge-0.2.0 → arraybridge-0.2.9}/src/arraybridge/exceptions.py +0 -0
  96. {arraybridge-0.2.0 → arraybridge-0.2.9}/tests/__init__.py +0 -0
@@ -0,0 +1 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="114" height="20" role="img" aria-label="coverage: 77.70%"><title>coverage: 77.70%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="114" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="61" height="20" fill="#555"/><rect x="61" width="53" height="20" fill="#97ca00"/><rect width="114" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="315" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="510">coverage</text><text x="315" y="140" transform="scale(.1)" fill="#fff" textLength="510">coverage</text><text aria-hidden="true" x="865" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="430">77.70%</text><text x="865" y="140" transform="scale(.1)" fill="#fff" textLength="430">77.70%</text></g></svg>
@@ -0,0 +1,158 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main, master]
6
+ pull_request:
7
+ branches: [main, master]
8
+ workflow_dispatch:
9
+
10
+ jobs:
11
+ # Test across Python versions with CPU-compatible frameworks (no torch)
12
+ test:
13
+ runs-on: ${{ matrix.os }}
14
+ strategy:
15
+ fail-fast: false
16
+ matrix:
17
+ python-version: ["3.10", "3.11", "3.12", "3.13"]
18
+ os: [ubuntu-latest, windows-latest, macos-latest]
19
+
20
+ steps:
21
+ - name: Checkout
22
+ uses: actions/checkout@v4
23
+
24
+ - name: Setup Python ${{ matrix.python-version }}
25
+ uses: actions/setup-python@v5
26
+ with:
27
+ python-version: ${{ matrix.python-version }}
28
+
29
+ - name: Install base dependencies
30
+ run: |
31
+ python -m pip install --upgrade pip
32
+ pip install -e ".[dev]"
33
+
34
+ - name: Run tests with coverage
35
+ run: |
36
+ pytest --cov=arraybridge --cov-report=xml --cov-report=html --cov-report=term-missing -v
37
+
38
+ - name: Upload coverage to Codecov
39
+ if: matrix.os == 'ubuntu-latest' && matrix.python-version == '3.12'
40
+ uses: codecov/codecov-action@v3
41
+ with:
42
+ file: ./coverage.xml
43
+ fail_ci_if_error: false
44
+
45
+ # GPU tests - includes framework testing
46
+ # Note: GitHub Actions ubuntu-latest doesn't have physical GPU,
47
+ # but tests will run the "unavailable GPU" code paths and mock GPU tests
48
+ gpu-test:
49
+ runs-on: ubuntu-latest
50
+ continue-on-error: true # Don't block PR merges if GPU not available
51
+
52
+ steps:
53
+ - name: Checkout
54
+ uses: actions/checkout@v4
55
+
56
+ - name: Setup Python
57
+ uses: actions/setup-python@v5
58
+ with:
59
+ python-version: "3.12"
60
+
61
+ - name: Install base dependencies
62
+ run: |
63
+ python -m pip install --upgrade pip
64
+ pip install -e ".[dev]"
65
+
66
+ - name: Install GPU frameworks (will use CPU versions in CI)
67
+ run: |
68
+ # PyTorch - CPU version will be installed in CI (no GPU available)
69
+ pip install torch torchvision torchaudio 2>&1 || echo "PyTorch install attempted"
70
+
71
+ # JAX - CPU version
72
+ pip install jax jaxlib 2>&1 || echo "JAX install skipped (optional)"
73
+
74
+ # CuPy - will fail without CUDA, that's ok
75
+ pip install cupy-cuda12x 2>&1 || echo "CuPy skipped (requires actual CUDA)"
76
+
77
+ - name: Check framework availability
78
+ run: |
79
+ python -c "
80
+ print('=== Framework Availability Check ===')
81
+ try:
82
+ import torch
83
+ print(f'✓ PyTorch available')
84
+ print(f' CUDA available: {torch.cuda.is_available()}')
85
+ print(f' (This is normal - GitHub Actions has no physical GPU)')
86
+ except ImportError:
87
+ print('✗ PyTorch not available')
88
+
89
+ try:
90
+ import jax
91
+ print(f'✓ JAX available')
92
+ except ImportError:
93
+ print('✗ JAX not available')
94
+
95
+ try:
96
+ import cupy
97
+ print(f'✓ CuPy available')
98
+ except ImportError:
99
+ print('✗ CuPy not available (normal - requires CUDA)')
100
+ " || true
101
+
102
+ - name: Run GPU cleanup tests
103
+ run: |
104
+ # Tests include:
105
+ # 1. Framework unavailable tests (always run)
106
+ # 2. GPU unavailable fallback paths (will run in CI)
107
+ # 3. Mocked GPU tests (test cleanup code with mocked GPU state)
108
+ pytest -v tests/test_gpu_cleanup.py \
109
+ --cov=arraybridge \
110
+ --cov-report=term-missing \
111
+ --cov-report=html \
112
+ --cov-report=xml \
113
+ -ra
114
+
115
+ - name: Upload GPU test coverage to Codecov
116
+ uses: codecov/codecov-action@v3
117
+ with:
118
+ file: ./coverage.xml
119
+ flags: gpu-tests
120
+ fail_ci_if_error: false
121
+
122
+ - name: Upload HTML coverage report
123
+ if: always()
124
+ uses: actions/upload-artifact@v4
125
+ with:
126
+ name: gpu-test-coverage-report
127
+ path: htmlcov/
128
+
129
+ # Code quality checks
130
+ code-quality:
131
+ runs-on: ubuntu-latest
132
+
133
+ steps:
134
+ - name: Checkout
135
+ uses: actions/checkout@v4
136
+
137
+ - name: Setup Python
138
+ uses: actions/setup-python@v5
139
+ with:
140
+ python-version: "3.12"
141
+
142
+ - name: Install dependencies
143
+ run: |
144
+ python -m pip install --upgrade pip
145
+ pip install ruff black mypy
146
+
147
+ - name: Run ruff (linting)
148
+ run: |
149
+ ruff check src/ --output-format=github
150
+
151
+ - name: Run black (formatting check)
152
+ run: |
153
+ black --check src/
154
+
155
+ - name: Run mypy (type checking)
156
+ continue-on-error: true # Scientific code often has complex types
157
+ run: |
158
+ mypy src/ --ignore-missing-imports
@@ -0,0 +1,115 @@
1
+ name: Tests, Coverage and GitHub Pages
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ workflow_dispatch:
7
+
8
+ permissions:
9
+ contents: write # Needed for badge commit
10
+ pages: write
11
+ id-token: write
12
+
13
+ concurrency:
14
+ group: "pages"
15
+ cancel-in-progress: true
16
+
17
+ jobs:
18
+ test-and-deploy:
19
+ runs-on: ubuntu-latest
20
+ environment:
21
+ name: github-pages
22
+ url: ${{ steps.deployment.outputs.page_url }}
23
+ steps:
24
+ - name: Checkout
25
+ uses: actions/checkout@v4
26
+
27
+ - name: Setup Python
28
+ uses: actions/setup-python@v5
29
+ with:
30
+ python-version: "3.12"
31
+
32
+ - name: Install dependencies
33
+ run: |
34
+ python -m pip install --upgrade pip
35
+ pip install -e ".[dev]"
36
+ pip install genbadge[coverage]
37
+
38
+ - name: Install PyTorch (CPU-only) for tests
39
+ run: |
40
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
41
+
42
+ - name: Run tests with coverage
43
+ continue-on-error: true # Continue workflow even if tests fail
44
+ run: |
45
+ mkdir -p site
46
+ python -m pytest --cov=arraybridge \
47
+ --cov-report=xml \
48
+ --cov-report=html:site/coverage \
49
+ tests/
50
+
51
+ - name: Generate coverage badge
52
+ run: |
53
+ mkdir -p .github/badges
54
+ genbadge coverage -i coverage.xml -o .github/badges/coverage.svg -n "coverage"
55
+
56
+ - name: Create index.html and README
57
+ run: |
58
+ # Create index.html for redirection
59
+ cat > site/index.html << 'EOF'
60
+ <!DOCTYPE html>
61
+ <html>
62
+ <head>
63
+ <meta http-equiv="refresh" content="0; url=./coverage/">
64
+ <title>Redirecting to coverage report...</title>
65
+ </head>
66
+ <body>
67
+ <p>Redirecting to coverage report... <a href="./coverage/">Click here if not redirected</a></p>
68
+ </body>
69
+ </html>
70
+ EOF
71
+
72
+ # Create README.md in the site directory
73
+ echo "# arraybridge Code Coverage Reports" > site/README.md
74
+ echo "" >> site/README.md
75
+ echo "This site contains the code coverage reports for the [arraybridge](https://github.com/trissim/arraybridge) project." >> site/README.md
76
+ echo "" >> site/README.md
77
+ echo "## Navigation" >> site/README.md
78
+ echo "" >> site/README.md
79
+ echo "- [Coverage Report](./coverage/): View the HTML coverage report" >> site/README.md
80
+ echo "" >> site/README.md
81
+ echo "## About" >> site/README.md
82
+ echo "" >> site/README.md
83
+ echo "These reports are automatically generated by GitHub Actions whenever changes are pushed to the main branch." >> site/README.md
84
+ echo "They show the percentage of code that is covered by automated tests." >> site/README.md
85
+ echo "" >> site/README.md
86
+ echo "Last updated: $(date)" >> site/README.md
87
+
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
+ - name: Check GitHub Pages status
98
+ run: |
99
+ echo "⚠️ IMPORTANT: Make sure GitHub Pages is enabled in your repository settings!"
100
+ echo "Go to https://github.com/trissim/arraybridge/settings/pages"
101
+ echo "Set 'Source' to 'GitHub Actions' to enable GitHub Pages deployment."
102
+
103
+ - name: Setup Pages
104
+ uses: actions/configure-pages@v4
105
+
106
+ - name: Upload Pages artifact
107
+ uses: actions/upload-pages-artifact@v3
108
+ with:
109
+ path: 'site'
110
+ retention-days: 1
111
+
112
+ - name: Deploy to GitHub Pages
113
+ id: deployment
114
+ uses: actions/deploy-pages@v4
115
+ timeout-minutes: 10
@@ -0,0 +1,79 @@
1
+ name: GPU Tests (Manual - Comprehensive GPU Testing)
2
+
3
+ on:
4
+ workflow_dispatch: # Manual trigger only
5
+
6
+ jobs:
7
+ gpu-test:
8
+ runs-on: ubuntu-latest
9
+
10
+ steps:
11
+ - name: Checkout
12
+ uses: actions/checkout@v4
13
+
14
+ - name: Setup Python
15
+ uses: actions/setup-python@v5
16
+ with:
17
+ python-version: "3.12"
18
+
19
+ - name: Install base dependencies
20
+ run: |
21
+ python -m pip install --upgrade pip
22
+ pip install -e ".[dev]"
23
+
24
+ - name: Install CPU-available frameworks
25
+ run: |
26
+ # Install CPU versions of frameworks for testing
27
+ # (Real GPU tests would need actual CUDA infrastructure)
28
+ pip install torch --index-url https://download.pytorch.org/whl/cpu
29
+ pip install jax jaxlib
30
+ echo "Installed PyTorch (CPU) and JAX for testing"
31
+
32
+ - name: Check framework availability
33
+ run: |
34
+ python -c "
35
+ import sys
36
+ frameworks = ['numpy', 'torch', 'jax', 'cupy', 'tensorflow', 'pyclesperanto']
37
+ for fw in frameworks:
38
+ try:
39
+ __import__(fw)
40
+ print(f'✓ {fw} available')
41
+ except ImportError:
42
+ print(f'✗ {fw} not available (will be skipped)')
43
+ "
44
+
45
+ - name: Run comprehensive GPU cleanup tests
46
+ run: |
47
+ # Run all GPU cleanup tests
48
+ # Tests will use frameworks if available, skip gracefully if not
49
+ pytest -v tests/test_gpu_cleanup.py \
50
+ --cov=arraybridge \
51
+ --cov-report=term-missing \
52
+ --cov-report=html \
53
+ --tb=short \
54
+ -ra
55
+
56
+ - name: Run framework-specific GPU tests
57
+ run: |
58
+ # Run tests marked for specific frameworks
59
+ pytest -v tests/ -k "gpu or cupy or torch or tensorflow or jax or pyclesperanto" \
60
+ --cov=arraybridge \
61
+ --cov-report=term-missing \
62
+ -ra || true
63
+
64
+ - name: Test results summary
65
+ if: always()
66
+ run: |
67
+ echo "GPU Testing Complete!"
68
+ echo "Note: Full GPU testing requires NVIDIA CUDA infrastructure."
69
+ echo "For complete GPU testing, use a system with NVIDIA GPUs installed."
70
+
71
+ - name: Upload coverage report
72
+ if: always()
73
+ uses: actions/upload-artifact@v4
74
+ with:
75
+ name: gpu-test-coverage-report
76
+ path: |
77
+ htmlcov/
78
+ .coverage
79
+
@@ -0,0 +1,215 @@
1
+ # Adding New Frameworks to arraybridge
2
+
3
+ With the metaclass-registry integration, adding a new framework is now simpler and requires no manual wiring.
4
+
5
+ ## Quick Overview
6
+
7
+ To add a new framework (e.g., MXNet), you need to:
8
+
9
+ 1. Add the new memory type to the `MemoryType` enum in `types.py`
10
+ 2. Add framework configuration to `_FRAMEWORK_CONFIG` in `framework_config.py`
11
+ 3. The converter automatically registers itself - no manual registration needed!
12
+
13
+ ## Step-by-Step Guide
14
+
15
+ ### Step 1: Add to MemoryType Enum
16
+
17
+ Edit `src/arraybridge/types.py`:
18
+
19
+ ```python
20
+ class MemoryType(Enum):
21
+ """Enum representing different array/tensor framework types."""
22
+
23
+ NUMPY = "numpy"
24
+ CUPY = "cupy"
25
+ TORCH = "torch"
26
+ TENSORFLOW = "tensorflow"
27
+ JAX = "jax"
28
+ PYCLESPERANTO = "pyclesperanto"
29
+ MXNET = "mxnet" # <-- Add your new framework
30
+ ```
31
+
32
+ ### Step 2: Add Framework Configuration
33
+
34
+ Edit `src/arraybridge/framework_config.py` and add a new entry to `_FRAMEWORK_CONFIG`:
35
+
36
+ ```python
37
+ _FRAMEWORK_CONFIG = {
38
+ # ... existing configurations ...
39
+
40
+ MemoryType.MXNET: {
41
+ # Metadata
42
+ 'import_name': 'mxnet',
43
+ 'display_name': 'MXNet',
44
+ 'is_gpu': True,
45
+
46
+ # Conversion operations - these define the converter methods
47
+ 'conversion_ops': {
48
+ 'to_numpy': 'data.asnumpy()', # How to convert to numpy
49
+ 'from_numpy': '{mod}.nd.array(data, ctx={mod}.gpu(gpu_id))', # How to create from numpy
50
+ 'from_dlpack': '{mod}.nd.from_dlpack(data)', # DLPack support (if available)
51
+ 'move_to_device': 'data.as_in_context({mod}.gpu(device_id))', # Move between devices
52
+ },
53
+
54
+ # Device operations (optional)
55
+ 'get_device_id': 'data.context.device_id',
56
+ 'set_device': None,
57
+
58
+ # Other configuration...
59
+ 'supports_dlpack': True,
60
+ 'validate_dlpack': None,
61
+
62
+ # ... add other required fields based on existing frameworks
63
+ }
64
+ }
65
+ ```
66
+
67
+ ### Step 3: That's It!
68
+
69
+ The converter class is automatically created and registered when the module loads. You can verify it works:
70
+
71
+ ```python
72
+ from arraybridge.converters_registry import ConverterBase, get_converter
73
+ from arraybridge.types import MemoryType
74
+
75
+ # Check that it's registered
76
+ print(sorted(ConverterBase.__registry__.keys()))
77
+ # Output: ['cupy', 'jax', 'mxnet', 'numpy', 'pyclesperanto', 'tensorflow', 'torch']
78
+
79
+ # Get the converter
80
+ mxnet_converter = get_converter("mxnet")
81
+ print(mxnet_converter.memory_type) # Output: 'mxnet'
82
+
83
+ # Use via MemoryType enum
84
+ converter = MemoryType.MXNET.converter
85
+ ```
86
+
87
+ ## What Happens Behind the Scenes
88
+
89
+ 1. **Auto-generation**: A `MxnetConverter` class is created dynamically with methods from `conversion_ops`
90
+ 2. **Auto-registration**: The metaclass `AutoRegisterMeta` automatically registers it in `ConverterBase.__registry__`
91
+ 3. **Auto-validation**: Module load validates that all `MemoryType` values have registered converters
92
+ 4. **Auto-methods**: The converter automatically gets `to_X()` methods for all other frameworks
93
+
94
+ ## Benefits of This Approach
95
+
96
+ ### Before (Manual Wiring - Old System)
97
+ ```python
98
+ # Had to manually create converter class with all methods
99
+ class MxnetConverter(MemoryTypeConverter):
100
+ def to_numpy(self, data, gpu_id):
101
+ return data.asnumpy()
102
+ def from_numpy(self, data, gpu_id):
103
+ return mxnet.nd.array(data)
104
+ def to_torch(self, data, gpu_id):
105
+ # ... manual implementation
106
+ def to_cupy(self, data, gpu_id):
107
+ # ... manual implementation
108
+ # ... 6+ more methods
109
+
110
+ # Had to manually register
111
+ _CONVERTERS[MemoryType.MXNET] = MxnetConverter()
112
+ ```
113
+
114
+ ### After (Auto-registration - New System)
115
+ ```python
116
+ # Just add to enum and config - everything else is automatic!
117
+ MemoryType.MXNET = "mxnet"
118
+
119
+ _FRAMEWORK_CONFIG[MemoryType.MXNET] = {
120
+ 'conversion_ops': {
121
+ 'to_numpy': 'data.asnumpy()',
122
+ # ...
123
+ }
124
+ }
125
+ ```
126
+
127
+ ## Framework Configuration Reference
128
+
129
+ Required fields in `conversion_ops`:
130
+ - `to_numpy`: Expression to convert framework data to numpy
131
+ - `from_numpy`: Expression to create framework data from numpy
132
+ - `from_dlpack`: Expression for DLPack conversion (or `None`)
133
+ - `move_to_device`: Expression to move data between devices
134
+
135
+ Available template variables in expressions:
136
+ - `{mod}`: The imported module (e.g., `mxnet`)
137
+ - `data`: The input data
138
+ - `gpu_id` / `device_id`: Target device ID
139
+
140
+ ## Testing Your New Framework
141
+
142
+ Add tests in `tests/test_converters.py`:
143
+
144
+ ```python
145
+ @pytest.mark.mxnet
146
+ def test_convert_numpy_to_mxnet(self, mxnet_available):
147
+ """Test converting NumPy to MXNet."""
148
+ if not mxnet_available:
149
+ pytest.skip("MXNet not available")
150
+
151
+ import mxnet as mx
152
+ arr = np.array([1.0, 2.0, 3.0], dtype=np.float32)
153
+ result = convert_memory(arr, source_type="numpy", target_type="mxnet", gpu_id=0)
154
+
155
+ assert isinstance(result, mx.nd.NDArray)
156
+ np.testing.assert_array_almost_equal(result.asnumpy(), arr)
157
+ ```
158
+
159
+ ## Common Patterns
160
+
161
+ ### GPU Framework with DLPack
162
+ ```python
163
+ 'conversion_ops': {
164
+ 'to_numpy': 'data.cpu().numpy()',
165
+ 'from_numpy': '{mod}.from_numpy(data).to(device=gpu_id)',
166
+ 'from_dlpack': '{mod}.from_dlpack(data)',
167
+ 'move_to_device': 'data.to(device=device_id)',
168
+ }
169
+ ```
170
+
171
+ ### CPU-only Framework
172
+ ```python
173
+ 'conversion_ops': {
174
+ 'to_numpy': 'np.array(data)',
175
+ 'from_numpy': '{mod}.array(data)',
176
+ 'from_dlpack': None, # Not supported
177
+ 'move_to_device': 'data', # No-op for CPU
178
+ }
179
+ ```
180
+
181
+ ### Complex Operations with Helpers
182
+ If you need complex logic, define a helper function in `framework_config.py`:
183
+
184
+ ```python
185
+ def _mxnet_special_conversion(data, gpu_id, mod):
186
+ # Complex logic here
187
+ return result
188
+
189
+ _FRAMEWORK_CONFIG[MemoryType.MXNET] = {
190
+ 'conversion_ops': {
191
+ 'from_numpy': _mxnet_special_conversion, # Use callable instead of string
192
+ # ...
193
+ }
194
+ }
195
+ ```
196
+
197
+ ## Troubleshooting
198
+
199
+ ### Converter not registered
200
+ Make sure:
201
+ 1. You added the framework to `MemoryType` enum
202
+ 2. You added configuration to `_FRAMEWORK_CONFIG`
203
+ 3. The key in `_FRAMEWORK_CONFIG` matches the `MemoryType` enum value
204
+
205
+ ### Import errors
206
+ If you get import errors, check:
207
+ 1. The `import_name` matches the actual package name
208
+ 2. The `conversion_ops` expressions use correct module syntax
209
+
210
+ ### Validation errors
211
+ Run this to check registration:
212
+ ```python
213
+ from arraybridge.converters_registry import _validate_registry
214
+ _validate_registry() # Raises RuntimeError if validation fails
215
+ ```
@@ -0,0 +1,47 @@
1
+ # GitHub Actions upload-artifact v3 → v4 Migration
2
+
3
+ ## Issue
4
+ GitHub deprecated `actions/upload-artifact@v3` effective April 16, 2024. The CI workflows were failing with:
5
+ ```
6
+ Error: This request has been automatically failed because it uses a deprecated version of `actions/upload-artifact: v3`.
7
+ ```
8
+
9
+ ## Solution
10
+ Updated all `upload-artifact` action references from `v3` to `v4` in CI workflows.
11
+
12
+ ## Files Updated
13
+
14
+ ### 1. `.github/workflows/ci.yml`
15
+ **Line 91**: Updated GPU test artifact upload
16
+ ```yaml
17
+ # Before
18
+ uses: actions/upload-artifact@v3
19
+
20
+ # After
21
+ uses: actions/upload-artifact@v4
22
+ ```
23
+
24
+ ### 2. `.github/workflows/gpu-tests.yml`
25
+ **Line 41**: Updated standalone GPU test artifact upload
26
+ ```yaml
27
+ # Before
28
+ uses: actions/upload-artifact@v3
29
+
30
+ # After
31
+ uses: actions/upload-artifact@v4
32
+ ```
33
+
34
+ ## Changes Made
35
+ - ✅ Both workflow files now use `actions/upload-artifact@v4`
36
+ - ✅ Artifact upload configuration remains the same
37
+ - ✅ CI workflows will no longer fail due to deprecated action
38
+
39
+ ## Reference
40
+ - [GitHub Blog: Deprecation Notice for Artifact Actions](https://github.blog/changelog/2024-04-16-deprecation-notice-v3-of-the-artifact-actions/)
41
+ - [Upload Artifact v4 Documentation](https://github.com/actions/upload-artifact/releases/tag/v4)
42
+
43
+ ## Verification
44
+ The GPU test CI job should now:
45
+ 1. ✅ Run without the deprecation error
46
+ 2. ✅ Successfully upload test results and coverage reports
47
+ 3. ✅ Display artifacts in the GitHub Actions UI