XuPy 1.6.1__tar.gz → 1.7.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.
Files changed (29) hide show
  1. {xupy-1.6.1 → xupy-1.7.1}/PKG-INFO +1 -1
  2. {xupy-1.6.1 → xupy-1.7.1}/XuPy.egg-info/PKG-INFO +1 -1
  3. {xupy-1.6.1 → xupy-1.7.1}/XuPy.egg-info/SOURCES.txt +1 -0
  4. {xupy-1.6.1 → xupy-1.7.1}/pyproject.toml +1 -1
  5. {xupy-1.6.1 → xupy-1.7.1}/test/test_core.py +1 -1
  6. xupy-1.7.1/test/test_cpu_memory_context.py +123 -0
  7. {xupy-1.6.1 → xupy-1.7.1}/xupy/__init__.py +1 -3
  8. xupy-1.7.1/xupy/__version__.py +1 -0
  9. {xupy-1.6.1 → xupy-1.7.1}/xupy/_core.py +577 -73
  10. {xupy-1.6.1 → xupy-1.7.1}/xupy/_cupy_install/__install_cupy__.py +1 -1
  11. {xupy-1.6.1 → xupy-1.7.1}/xupy/ma/core.py +4 -0
  12. {xupy-1.6.1 → xupy-1.7.1}/xupy/ma/extras.py +82 -82
  13. xupy-1.6.1/xupy/__version__.py +0 -1
  14. {xupy-1.6.1 → xupy-1.7.1}/LICENSE +0 -0
  15. {xupy-1.6.1 → xupy-1.7.1}/README.md +0 -0
  16. {xupy-1.6.1 → xupy-1.7.1}/XuPy.egg-info/dependency_links.txt +0 -0
  17. {xupy-1.6.1 → xupy-1.7.1}/XuPy.egg-info/requires.txt +0 -0
  18. {xupy-1.6.1 → xupy-1.7.1}/XuPy.egg-info/top_level.txt +0 -0
  19. {xupy-1.6.1 → xupy-1.7.1}/setup.cfg +0 -0
  20. {xupy-1.6.1 → xupy-1.7.1}/setup.py +0 -0
  21. {xupy-1.6.1 → xupy-1.7.1}/test/test_arithmetic_compatibility.py +0 -0
  22. {xupy-1.6.1 → xupy-1.7.1}/test/test_large_array_printing.py +0 -0
  23. {xupy-1.6.1 → xupy-1.7.1}/test/test_ma_core.py +0 -0
  24. {xupy-1.6.1 → xupy-1.7.1}/test/test_ma_extras.py +0 -0
  25. {xupy-1.6.1 → xupy-1.7.1}/xupy/_cupy_install/__check_availability__.py +0 -0
  26. {xupy-1.6.1 → xupy-1.7.1}/xupy/_cupy_install/__init__.py +0 -0
  27. {xupy-1.6.1 → xupy-1.7.1}/xupy/ma/__init__.py +0 -0
  28. {xupy-1.6.1 → xupy-1.7.1}/xupy/py.typed +0 -0
  29. {xupy-1.6.1 → xupy-1.7.1}/xupy/typings.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: XuPy
3
- Version: 1.6.1
3
+ Version: 1.7.1
4
4
  Summary: GPU Accelerated masked arrays with automatic handling of CPU and GPU arrays.
5
5
  Author: Pietro Ferraiuolo
6
6
  Author-email: Pietro Ferraiuolo <pietro.ferraiuolo@inaf.it>
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: XuPy
3
- Version: 1.6.1
3
+ Version: 1.7.1
4
4
  Summary: GPU Accelerated masked arrays with automatic handling of CPU and GPU arrays.
5
5
  Author: Pietro Ferraiuolo
6
6
  Author-email: Pietro Ferraiuolo <pietro.ferraiuolo@inaf.it>
@@ -9,6 +9,7 @@ XuPy.egg-info/requires.txt
9
9
  XuPy.egg-info/top_level.txt
10
10
  test/test_arithmetic_compatibility.py
11
11
  test/test_core.py
12
+ test/test_cpu_memory_context.py
12
13
  test/test_large_array_printing.py
13
14
  test/test_ma_core.py
14
15
  test/test_ma_extras.py
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "XuPy"
7
- version = "1.6.1"
7
+ version = "1.7.1"
8
8
  description = "GPU Accelerated masked arrays with automatic handling of CPU and GPU arrays."
9
9
  authors = [
10
10
  { name = "Pietro Ferraiuolo", email = "pietro.ferraiuolo@inaf.it" }
@@ -19,7 +19,7 @@ except ImportError:
19
19
  HAS_CUPY = False
20
20
 
21
21
  import xupy as xp
22
- from xupy._core import NumpyContext, on_gpu
22
+ from xupy._core import NumpyContext, _CPUMemoryContext, on_gpu
23
23
 
24
24
  # Skip all tests if CuPy is not available
25
25
  pytestmark = pytest.mark.skipif(not HAS_CUPY, reason="CuPy not available")
@@ -0,0 +1,123 @@
1
+ """
2
+ Tests for _CPUMemoryContext.
3
+
4
+ These tests do NOT require CuPy/CUDA and run purely on CPU (NumPy).
5
+ They validate that the CPU memory context manager exposes the same
6
+ interface as the GPU MemoryContext and behaves as a well-behaved
7
+ no-op context on CPU.
8
+ """
9
+ import pytest
10
+ import numpy as np
11
+
12
+ import xupy as xp
13
+ from xupy._core import _CPUMemoryContext, on_gpu
14
+
15
+
16
+ class TestCPUMemoryContext:
17
+ """Tests for _CPUMemoryContext (always available, no GPU required)."""
18
+
19
+ def test_cpu_memory_context_is_importable(self):
20
+ """_CPUMemoryContext can be imported from _core and is a class."""
21
+ assert callable(_CPUMemoryContext)
22
+
23
+ def test_cpu_memory_context_enter_returns_self(self):
24
+ """__enter__ returns the context object itself."""
25
+ ctx = _CPUMemoryContext()
26
+ with ctx as c:
27
+ assert c is ctx
28
+
29
+ def test_cpu_memory_context_basic_usage(self, capsys):
30
+ """Context manager completes without raising and prints a summary."""
31
+ with _CPUMemoryContext() as ctx:
32
+ arr = np.array([1, 2, 3])
33
+ assert arr is not None
34
+ captured = capsys.readouterr()
35
+ assert "Session completed" in captured.out
36
+
37
+ def test_cpu_memory_context_default_parameters(self):
38
+ """Default parameters match the GPU MemoryContext API."""
39
+ ctx = _CPUMemoryContext()
40
+ assert ctx.device_id is None
41
+ assert ctx.auto_cleanup is True
42
+ assert ctx.memory_threshold == 0.9
43
+ assert ctx.monitor_interval == 1.0
44
+
45
+ def test_cpu_memory_context_custom_parameters(self):
46
+ """Custom parameters are stored correctly."""
47
+ ctx = _CPUMemoryContext(
48
+ device_id=0,
49
+ auto_cleanup=False,
50
+ memory_threshold=0.8,
51
+ monitor_interval=2.0,
52
+ )
53
+ assert ctx.device_id == 0
54
+ assert ctx.auto_cleanup is False
55
+ assert ctx.memory_threshold == 0.8
56
+ assert ctx.monitor_interval == 2.0
57
+
58
+ def test_cpu_memory_context_get_memory_info_returns_dict(self):
59
+ """get_memory_info always returns a dict with at least 'device'."""
60
+ ctx = _CPUMemoryContext()
61
+ info = ctx.get_memory_info()
62
+ assert isinstance(info, dict)
63
+ assert "device" in info
64
+ assert info["device"] == "cpu"
65
+
66
+ def test_cpu_memory_context_get_memory_info_keys(self):
67
+ """get_memory_info returns expected keys when psutil is available."""
68
+ try:
69
+ import psutil # noqa: F401
70
+ psutil_available = True
71
+ except ImportError:
72
+ psutil_available = False
73
+
74
+ ctx = _CPUMemoryContext()
75
+ info = ctx.get_memory_info()
76
+ if psutil_available:
77
+ for key in ("total", "free", "used", "memory_percent"):
78
+ assert key in info, f"Missing key '{key}' in memory info"
79
+ assert info["total"] > 0
80
+ assert 0.0 <= info["memory_percent"] <= 1.0
81
+ else:
82
+ assert "error" in info
83
+
84
+ def test_cpu_memory_context_no_op_methods(self):
85
+ """All GPU-specific methods are no-ops (do not raise)."""
86
+ ctx = _CPUMemoryContext()
87
+ ctx.track_object(object())
88
+ ctx.clear_cache()
89
+ ctx.aggressive_cleanup()
90
+ ctx.emergency_cleanup()
91
+ ctx.auto_cleanup_if_needed()
92
+ ctx.monitor_memory(duration=0.0)
93
+ ctx.force_memory_deallocation()
94
+ ctx.force_memory_pool_reset()
95
+
96
+ def test_cpu_memory_context_check_memory_pressure(self):
97
+ """check_memory_pressure returns a bool."""
98
+ ctx = _CPUMemoryContext()
99
+ result = ctx.check_memory_pressure()
100
+ assert isinstance(result, bool)
101
+
102
+ def test_cpu_memory_context_repr(self):
103
+ """__repr__ contains 'MemoryContext' and 'cpu'."""
104
+ ctx = _CPUMemoryContext()
105
+ r = repr(ctx)
106
+ assert "MemoryContext" in r
107
+ assert "cpu" in r
108
+
109
+ def test_cpu_memory_context_exception_propagation(self):
110
+ """Exceptions raised inside the context propagate normally."""
111
+ with pytest.raises(ValueError):
112
+ with _CPUMemoryContext():
113
+ raise ValueError("test error")
114
+
115
+ def test_cpu_memory_context_exposed_when_on_cpu(self):
116
+ """When running in CPU mode, xp.MemoryContext is _CPUMemoryContext."""
117
+ if not on_gpu:
118
+ assert hasattr(xp, "MemoryContext")
119
+ assert xp.MemoryContext is _CPUMemoryContext
120
+
121
+
122
+ if __name__ == "__main__":
123
+ pytest.main([__file__, "-v"])
@@ -4,6 +4,4 @@ XuPy: A library with authomatic handling of GPU and CPU arrays.
4
4
 
5
5
  from ._core import *
6
6
  from .__version__ import __version__
7
-
8
- if on_gpu:
9
- from . import ma
7
+ from . import ma
@@ -0,0 +1 @@
1
+ __version__ = "1.7.1"