From aa77f9941fad8fe6d7b3c39d7391a759f84aded1 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 15 Oct 2026 12:49:37 +0200 Subject: [PATCH 1/3] Deprecate unused dpnp.config settings __DPNP_QUEUE_GPU__, __DPNP_OUTPUT_NUMPY__ and __DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__ are not used anywhere in dpnp. Reading them now emits a DeprecationWarning; they will be removed in a future release. --- dpnp/config.py | 39 ++++++++++++++++++++++----------------- dpnp/tests/test_config.py | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+), 17 deletions(-) create mode 100644 dpnp/tests/test_config.py diff --git a/dpnp/config.py b/dpnp/config.py index 0d973cdd298e..af004a990477 100644 --- a/dpnp/config.py +++ b/dpnp/config.py @@ -28,32 +28,37 @@ import os +import warnings __DPNP_ORIGIN__ = int(os.getenv("DPNP_ORIGIN", 0)) """ Explicitly use original host Python NumPy """ -__DPNP_QUEUE_GPU__ = int(os.getenv("DPNP_QUEUE_GPU", 0)) -""" -Explicitly use GPU for SYCL queue -""" - -__DPNP_OUTPUT_NUMPY__ = int(os.getenv("DPNP_OUTPUT_NUMPY", 0)) -""" -Explicitly use NumPy.ndarray as return type for creation functions -""" - -__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__ = int( - os.getenv("DPNP_OUTPUT_DPCTL_DEFAULT_SHARED", 0) -) -""" -Explicitly use SYCL shared memory parameter in DPCtl array constructor for creation functions -""" - __DPNP_RAISE_EXCEPION_ON_NUMPY_FALLBACK__ = int( os.getenv("DPNP_RAISE_EXCEPION_ON_NUMPY_FALLBACK", 1) ) """ Trigger non-implemented exception when DPNP fallbacks on NumPy implementation """ + +# settings that no longer have any effect, kept as deprecated attributes +_DEPRECATED_SETTINGS = { + "__DPNP_QUEUE_GPU__": int(os.getenv("DPNP_QUEUE_GPU", 0)), + "__DPNP_OUTPUT_NUMPY__": int(os.getenv("DPNP_OUTPUT_NUMPY", 0)), + "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__": int( + os.getenv("DPNP_OUTPUT_DPCTL_DEFAULT_SHARED", 0) + ), +} + + +def __getattr__(name): + if name in _DEPRECATED_SETTINGS: + warnings.warn( + f"`dpnp.config.{name}` is deprecated, and will be removed in a " + "future release. It has no effect.", + DeprecationWarning, + stacklevel=2, + ) + return _DEPRECATED_SETTINGS[name] + raise AttributeError(f"module {__name__!r} has no attribute {name!r}") diff --git a/dpnp/tests/test_config.py b/dpnp/tests/test_config.py new file mode 100644 index 000000000000..b33fa39c1247 --- /dev/null +++ b/dpnp/tests/test_config.py @@ -0,0 +1,22 @@ +import pytest + +import dpnp + + +class TestDeprecatedSettings: + @pytest.mark.parametrize( + "name", + [ + "__DPNP_QUEUE_GPU__", + "__DPNP_OUTPUT_NUMPY__", + "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__", + ], + ) + def test_warns(self, name): + with pytest.warns(DeprecationWarning, match="has no effect"): + value = getattr(dpnp.config, name) + assert isinstance(value, int) + + def test_unknown_name(self): + with pytest.raises(AttributeError, match="has no attribute"): + getattr(dpnp.config, "__DPNP_UNKNOWN__") From 1506d2bc1e7c503f625fc7b5daa43d7a05453d66 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 15 Oct 2026 12:50:01 +0200 Subject: [PATCH 2/3] Add a changelog entry --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d6b8161ef84..c62d963172ef 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,6 +62,7 @@ This release is compatible with NumPy 2.5. ### Deprecated * Deprecated setting the shape via the `shape` attribute of `dpnp.ndarray` and `dpnp.tensor.usm_ndarray`. Use `dpnp.reshape`/`dpnp.tensor.reshape` (or the `reshape` method) instead [#2967](https://github.com/IntelPython/dpnp/pull/2967) +* Deprecated `dpnp.config.__DPNP_QUEUE_GPU__`, `dpnp.config.__DPNP_OUTPUT_NUMPY__` and `dpnp.config.__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__`, which have no effect; reading them now emits a `DeprecationWarning` [#3107](https://github.com/IntelPython/dpnp/pull/3107) ### Removed From 13894ae95ba6d38c1da9ac57cff0d91596d3ea47 Mon Sep 17 00:00:00 2001 From: Anton Volkov Date: Thu, 22 Oct 2026 21:20:41 +0200 Subject: [PATCH 3/3] Address review comments Warn also on assignment to a deprecated dpnp.config setting, parse the deprecated env vars lazily so a bad value can't break import, drop the DPNP_QUEUE_GPU check from conftest, and extend the tests. --- CHANGELOG.md | 2 +- dpnp/config.py | 51 +++++++++++++++++++++++++++++---------- dpnp/tests/conftest.py | 2 +- dpnp/tests/test_config.py | 46 ++++++++++++++++++++++++++++++++--- 4 files changed, 83 insertions(+), 18 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c62d963172ef..84162fa7ed6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,7 +62,7 @@ This release is compatible with NumPy 2.5. ### Deprecated * Deprecated setting the shape via the `shape` attribute of `dpnp.ndarray` and `dpnp.tensor.usm_ndarray`. Use `dpnp.reshape`/`dpnp.tensor.reshape` (or the `reshape` method) instead [#2967](https://github.com/IntelPython/dpnp/pull/2967) -* Deprecated `dpnp.config.__DPNP_QUEUE_GPU__`, `dpnp.config.__DPNP_OUTPUT_NUMPY__` and `dpnp.config.__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__`, which have no effect; reading them now emits a `DeprecationWarning` [#3107](https://github.com/IntelPython/dpnp/pull/3107) +* Deprecated `dpnp.config.__DPNP_QUEUE_GPU__`, `dpnp.config.__DPNP_OUTPUT_NUMPY__` and `dpnp.config.__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__`, which have no effect; reading or setting them now emits a `DeprecationWarning` [#3107](https://github.com/IntelPython/dpnp/pull/3107) ### Removed diff --git a/dpnp/config.py b/dpnp/config.py index af004a990477..eb5e50237eff 100644 --- a/dpnp/config.py +++ b/dpnp/config.py @@ -28,6 +28,8 @@ import os +import sys +import types import warnings __DPNP_ORIGIN__ = int(os.getenv("DPNP_ORIGIN", 0)) @@ -42,23 +44,46 @@ Trigger non-implemented exception when DPNP fallbacks on NumPy implementation """ -# settings that no longer have any effect, kept as deprecated attributes +# settings that no longer have any effect: attribute name -> env var name _DEPRECATED_SETTINGS = { - "__DPNP_QUEUE_GPU__": int(os.getenv("DPNP_QUEUE_GPU", 0)), - "__DPNP_OUTPUT_NUMPY__": int(os.getenv("DPNP_OUTPUT_NUMPY", 0)), - "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__": int( - os.getenv("DPNP_OUTPUT_DPCTL_DEFAULT_SHARED", 0) - ), + "__DPNP_QUEUE_GPU__": "DPNP_QUEUE_GPU", + "__DPNP_OUTPUT_NUMPY__": "DPNP_OUTPUT_NUMPY", + "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__": "DPNP_OUTPUT_DPCTL_DEFAULT_SHARED", } +# values assigned to deprecated settings after import +_deprecated_values = {} + + +def _warn_deprecated(name): + warnings.warn( + f"`dpnp.config.{name}` is deprecated, and will be removed in a " + "future release. It has no effect.", + DeprecationWarning, + stacklevel=3, + ) + def __getattr__(name): if name in _DEPRECATED_SETTINGS: - warnings.warn( - f"`dpnp.config.{name}` is deprecated, and will be removed in a " - "future release. It has no effect.", - DeprecationWarning, - stacklevel=2, - ) - return _DEPRECATED_SETTINGS[name] + _warn_deprecated(name) + if name in _deprecated_values: + return _deprecated_values[name] + # parse lazily, so a bad env value can't break `import dpnp` + return int(os.getenv(_DEPRECATED_SETTINGS[name], 0)) raise AttributeError(f"module {__name__!r} has no attribute {name!r}") + + +class _ConfigModule(types.ModuleType): + """Warn also on assignment to a deprecated setting.""" + + def __setattr__(self, name, value): + if name in _DEPRECATED_SETTINGS: + _warn_deprecated(name) + # keep it out of the module dict, so reads still warn + _deprecated_values[name] = value + else: + super().__setattr__(name, value) + + +sys.modules[__name__].__class__ = _ConfigModule diff --git a/dpnp/tests/conftest.py b/dpnp/tests/conftest.py index c4cb94845db9..b37a33d930ac 100644 --- a/dpnp/tests/conftest.py +++ b/dpnp/tests/conftest.py @@ -159,7 +159,7 @@ def pytest_collection_modifyitems(config, items): print(f"NumPy version: {numpy.__version__}, location: {numpy}") print(f"Python version: {sys.version}") print("") - if is_gpu or os.getenv("DPNP_QUEUE_GPU") == "1": + if is_gpu: excluded_tests.extend(get_excluded_tests(test_exclude_file_gpu)) if not support_fp64: excluded_tests.extend( diff --git a/dpnp/tests/test_config.py b/dpnp/tests/test_config.py index b33fa39c1247..0984663bad01 100644 --- a/dpnp/tests/test_config.py +++ b/dpnp/tests/test_config.py @@ -1,9 +1,35 @@ +import re +import warnings + import pytest import dpnp +@pytest.fixture(autouse=True) +def reset_deprecated_values(monkeypatch): + # drop values assigned by other tests + monkeypatch.setattr(dpnp.config, "_deprecated_values", {}) + + class TestDeprecatedSettings: + @pytest.mark.parametrize( + "name, env", + [ + ("__DPNP_QUEUE_GPU__", "DPNP_QUEUE_GPU"), + ("__DPNP_OUTPUT_NUMPY__", "DPNP_OUTPUT_NUMPY"), + ( + "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__", + "DPNP_OUTPUT_DPCTL_DEFAULT_SHARED", + ), + ], + ) + def test_read_warns(self, monkeypatch, name, env): + monkeypatch.delenv(env, raising=False) + with pytest.warns(DeprecationWarning, match=re.escape(name)): + value = getattr(dpnp.config, name) + assert value == 0 + @pytest.mark.parametrize( "name", [ @@ -12,10 +38,24 @@ class TestDeprecatedSettings: "__DPNP_OUTPUT_DPCTL_DEFAULT_SHARED__", ], ) - def test_warns(self, name): - with pytest.warns(DeprecationWarning, match="has no effect"): + def test_write_warns(self, name): + with pytest.warns(DeprecationWarning, match=re.escape(name)): + setattr(dpnp.config, name, 1) + + # a later read must still warn + with pytest.warns(DeprecationWarning, match=re.escape(name)): + value = getattr(dpnp.config, name) + assert value == 1 + + @pytest.mark.parametrize( + "name", + ["__DPNP_ORIGIN__", "__DPNP_RAISE_EXCEPION_ON_NUMPY_FALLBACK__"], + ) + def test_no_warning(self, monkeypatch, name): + with warnings.catch_warnings(): + warnings.simplefilter("error") value = getattr(dpnp.config, name) - assert isinstance(value, int) + monkeypatch.setattr(dpnp.config, name, value) def test_unknown_name(self): with pytest.raises(AttributeError, match="has no attribute"):