Skip to content

Commit 8c5a79b

Browse files
authored
Merge pull request #14 from max-models/7-add-bools-for-numpy_backend-and-cupy_backend-for-conditional-statements
7 add bools for numpy backend and cupy backend for conditional statements
2 parents 431e047 + 34db713 commit 8c5a79b

6 files changed

Lines changed: 46 additions & 1 deletion

File tree

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1717
- **Global Backend Control**:
1818
- `xp.set_backend(name)`: Globally switch the active backend at runtime.
1919
- `xp.use_backend(name)`: Context manager for temporary, scoped backend switching.
20+
- `xp.numpy_backend` & `xp.cupy_backend`: Boolean properties to check the globally active backend.
2021
- **Synchronization**:
2122
- `xp.synchronize()`: Blocks until GPU operations are complete (no-op on CPU). Essential for accurate benchmarking.
2223
- **Developer Experience**:
@@ -25,7 +26,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2526
### Changed
2627
- **Dynamic Dispatch Architecture**: Refactored `src/cunumpy/xp.py` to use module-level `__getattr__`. This ensures that `cunumpy.<op>` calls always resolve to the currently active backend module, enabling seamless runtime switching via `set_backend`.
2728
- **Type Safety**: Updated `src/cunumpy/__init__.pyi` stubs to provide full IDE autocompletion and type-checking for all new API methods.
28-
- **Documentation**: Enhanced `README.md` with usage examples for the new backend control and synchronization features.
29+
- **Documentation**:
30+
- Simplified `README.md` and documentation to exclusively focus on PyPI installation (`pip install cunumpy`).
31+
- Enhanced `quickstart.md` and `api.md` with usage examples for the new backend control and synchronization features.
32+
- **CI/CD**: Restricted GitHub Pages documentation deployment to the `devel` branch only.
2933

3034
### Fixed
3135
- Improved `ArrayBackend` initialization to fallback gracefully to NumPy if CuPy is requested but not installed.

docs/source/api.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ Returns `True` if the array is stored on a CPU (NumPy).
2424

2525
## Global Configuration
2626

27+
### `numpy_backend`
28+
Boolean property that returns `True` if the currently active global backend is NumPy.
29+
30+
### `cupy_backend`
31+
Boolean property that returns `True` if the currently active global backend is CuPy.
32+
2733
### `set_backend(backend_name)`
2834
Globally sets the active backend for all `cunumpy` operations. `backend_name` should be `"numpy"` or `"cupy"`.
2935

src/cunumpy/__init__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,15 @@
2323
"use_backend",
2424
"set_backend",
2525
"synchronize",
26+
"numpy_backend",
27+
"cupy_backend",
2628
]
2729

2830

2931
def __getattr__(name: str):
3032
"""Set cunumpy.<name> to cunumpy.xp.<name> (NumPy/CuPy)."""
33+
if name == "numpy_backend":
34+
return xp.numpy_backend
35+
if name == "cupy_backend":
36+
return xp.cupy_backend
3137
return getattr(xp.xp, name)

src/cunumpy/__init__.pyi

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,6 @@ def is_cpu(array: Any) -> bool: ...
1919
def use_backend(backend: str) -> Generator[None, None, None]: ...
2020
def set_backend(backend: str) -> None: ...
2121
def synchronize() -> None: ...
22+
23+
numpy_backend: bool
24+
cupy_backend: bool

src/cunumpy/xp.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,16 @@ def set_backend(backend: BackendType) -> None:
9292
array_backend._xp = array_backend._load_backend(backend)
9393

9494

95+
def _cupy_backend() -> bool:
96+
"""Check if the active global backend is CuPy."""
97+
return array_backend.backend == "cupy"
98+
99+
100+
def _numpy_backend() -> bool:
101+
"""Check if the active global backend is NumPy."""
102+
return array_backend.backend == "numpy"
103+
104+
95105
def synchronize() -> None:
96106
"""Wait for all kernels in all streams on current device to complete."""
97107
if array_backend.backend == "cupy":
@@ -153,4 +163,8 @@ def is_cpu(array: Any) -> bool:
153163
def __getattr__(name):
154164
if name == "xp":
155165
return array_backend.xp
166+
if name == "numpy_backend":
167+
return _numpy_backend()
168+
if name == "cupy_backend":
169+
return _cupy_backend()
156170
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

tests/unit/test_app.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ def test_numpy_symbols_accessible():
2929
"use_backend",
3030
"set_backend",
3131
"synchronize",
32+
"numpy_backend",
33+
"cupy_backend",
3234
"xp",
3335
]
3436
missing = [
@@ -114,6 +116,16 @@ def test_synchronize():
114116
xp.synchronize()
115117

116118

119+
def test_backend_bools():
120+
with xp.use_backend("numpy"):
121+
assert xp.numpy_backend is True
122+
assert xp.cupy_backend is False
123+
124+
# Note: in test env without cupy, cupy_backend might be false
125+
# even inside use_backend('cupy') if fallback occurs.
126+
# Our implementation of use_backend calls _load_backend which returns np if cp missing.
127+
128+
117129
if __name__ == "__main__":
118130
test_xp_array()
119131
test_numpy_symbols_accessible()

0 commit comments

Comments
 (0)