From f519e263ebfa8aa9364f90804250bafe4604dcdb Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 05:48:42 -0800 Subject: [PATCH 01/14] Deprecate positional out argument in dpnp.minimum --- dpnp/dpnp_iface_mathematical.py | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index bd7e83ae3a8..478a4d9a025 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -47,6 +47,7 @@ import builtins import warnings +from functools import wraps import dpctl.tensor as dpt import dpctl.tensor._tensor_elementwise_impl as ti @@ -3344,7 +3345,7 @@ def interp(x, xp, fp, left=None, right=None, period=None): array(-inf) """ -minimum = DPNPBinaryFunc( +_minimum_impl = DPNPBinaryFunc( "minimum", ti._minimum_result_type, ti._minimum, @@ -3352,6 +3353,23 @@ def interp(x, xp, fp, left=None, right=None, period=None): ) +@wraps(_minimum_impl) +def minimum(*args, **kwargs): + """ + Wrapper around `_minimum_impl` that emits a DeprecationWarning + when `out` is passed positionally. + + """ + if len(args) >= 3 and "out" not in kwargs: + warnings.warn( + "Positional `out` argument to `dpnp.minimum` is deprecated. " + "Please use the keyword form, e.g. `dpnp.minimum(a, b, out=c)`.", + DeprecationWarning, + stacklevel=2, + ) + return _minimum_impl(*args, **kwargs) + + def modf(x1, **kwargs): """ Return the fractional and integral parts of an array, element-wise. From 83ace7997eef44b82d257801c2945fa3d9a83412 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 05:53:10 -0800 Subject: [PATCH 02/14] Deprecate positional out argument in dpnp.maximum --- dpnp/dpnp_iface_mathematical.py | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 478a4d9a025..f2c1fc4aede 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -3257,7 +3257,7 @@ def interp(x, xp, fp, left=None, right=None, period=None): """ -maximum = DPNPBinaryFunc( +_maximum_impl = DPNPBinaryFunc( "maximum", ti._maximum_result_type, ti._maximum, @@ -3265,6 +3265,23 @@ def interp(x, xp, fp, left=None, right=None, period=None): ) +@wraps(_maximum_impl) +def maximum(*args, **kwargs): + """ + Wrapper around `_maximum_impl` that emits a DeprecationWarning + when `out` is passed positionally. + + """ + if len(args) >= 3 and "out" not in kwargs: + warnings.warn( + "Positional `out` argument to `dpnp.maximum` is deprecated. " + "Please use the keyword form, e.g. `dpnp.maximum(a, b, out=c)`.", + DeprecationWarning, + stacklevel=2, + ) + return _maximum_impl(*args, **kwargs) + + _MINIMUM_DOCSTRING = """ Computes the minimum value for each element :math:`x1_i` of the input array `x1` relative to the respective element :math:`x2_i` of the input array `x2`. From 10ce7b6d978f01bb0b9c961e6667e47196a74f30 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 06:04:38 -0800 Subject: [PATCH 03/14] Add Warning section to maximum/minimum docs --- dpnp/dpnp_iface_mathematical.py | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index f2c1fc4aede..ac6b2740d59 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -3204,6 +3204,14 @@ def interp(x, xp, fp, left=None, right=None, period=None): Default: ``"K"``. +Warning +------- +Passing the output array ``out`` positionally is deprecated. +For example, ``dpnp.maximum(a, b, c)`` will emit a ``DeprecationWarning``. + +Always pass the output with the keyword form, e.g. +``dpnp.maximum(a, b, out=c)``. + Returns ------- out : dpnp.ndarray @@ -3316,6 +3324,14 @@ def maximum(*args, **kwargs): An array containing the element-wise minima. The data type of the returned array is determined by the Type Promotion Rules. +Warning +------- +Passing the output array ``out`` positionally is deprecated. +For example, ``dpnp.minimum(a, b, c)`` will emit a ``DeprecationWarning``. + +Always pass the output with the keyword form, e.g. +``dpnp.minimum(a, b, out=c)``. + Limitations ----------- Parameters `where` and `subok` are supported with their default values. From 74a0f02e22304327696f7915cedad5bda7a62102 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 06:31:36 -0800 Subject: [PATCH 04/14] Add warning test --- dpnp/tests/test_mathematical.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 8d4cdb426ae..2dbea16d87b 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -2910,3 +2910,13 @@ def test_elemenwise_outer_scalar(): expected = dpnp.add.outer(x, y) result = dpnp.add.outer(x, s) assert dpnp.allclose(result, expected) + + +@pytest.mark.parametrize("func", ["minimum", "maximum"]) +def test_minimum_maximum_out_deprecated(func): + a = dpnp.array([1, 3, 2]) + b = dpnp.array([2, 2, 2]) + out = dpnp.empty_like(a) + + with pytest.warns(DeprecationWarning, match="deprecated"): + _ = getattr(dpnp, func)(a, b, out) From c4e350d672c4a8d6089f764a7dc2d0b4abf73475 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 06:36:19 -0800 Subject: [PATCH 05/14] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1cd5de4e47c..9ded7461302 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum ### Deprecated * `dpnp.asfarray` is deprecated. Use `dpnp.asarray` with an appropriate dtype instead [#2650](https://github.com/IntelPython/dpnp/pull/2650) +* Passing the output array ``out`` positionally to `dpnp.minimum` and `dpnp.maximum` is deprecated. Pass the output with the keyword form, e.g. ``dpnp.minimum(a, b, out=c)`` [#2657](https://github.com/IntelPython/dpnp/pull/2657) ### Removed From 1cd390bf39375b561dd5cbd6f2a2473f728cb077 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Mon, 10 Nov 2025 06:47:37 -0800 Subject: [PATCH 06/14] Update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7de9e8065c6..a3fda5fc3a3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ Also, that release drops support for Python 3.9, making Python 3.10 the minimum ### Deprecated * `dpnp.asfarray` is deprecated. Use `dpnp.asarray` with an appropriate dtype instead [#2650](https://github.com/IntelPython/dpnp/pull/2650) -* Passing the output array ``out`` positionally to `dpnp.minimum` and `dpnp.maximum` is deprecated. Pass the output with the keyword form, e.g. ``dpnp.minimum(a, b, out=c)`` [#2657](https://github.com/IntelPython/dpnp/pull/2657) +* Passing the output array ``out`` positionally to `dpnp.minimum` and `dpnp.maximum` is deprecated. Pass the output with the keyword form, e.g. ``dpnp.minimum(a, b, out=c)`` [#2659](https://github.com/IntelPython/dpnp/pull/2659) ### Removed From 0090fb0939be93636307735e06b2a5092fa2bedc Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 01:36:03 -0800 Subject: [PATCH 07/14] Update Warning section to maximum/minimum docs --- dpnp/dpnp_iface_mathematical.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 5eedf07fc3e..c98fdc7947a 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -3205,10 +3205,12 @@ def interp(x, xp, fp, left=None, right=None, period=None): Warning ------- -Passing the output array ``out`` positionally is deprecated. -For example, ``dpnp.maximum(a, b, c)`` will emit a ``DeprecationWarning``. +Passing more than 2 positional arguments is deprecated. +If you meant to use the third argument as an output, +use the `out` keyword argument instead. -Always pass the output with the keyword form, e.g. +For example, ``dpnp.maximum(a, b, c)`` will emit a ``DeprecationWarning``. +Always pass the output array as the keyword argument instead, that is ``dpnp.maximum(a, b, out=c)``. Returns @@ -3325,10 +3327,12 @@ def maximum(*args, **kwargs): Warning ------- -Passing the output array ``out`` positionally is deprecated. -For example, ``dpnp.minimum(a, b, c)`` will emit a ``DeprecationWarning``. +Passing more than 2 positional arguments is deprecated. +If you meant to use the third argument as an output, +use the `out` keyword argument instead. -Always pass the output with the keyword form, e.g. +For example, ``dpnp.minimum(a, b, c)`` will emit a ``DeprecationWarning``. +Always pass the output array as the keyword argument instead, that is ``dpnp.minimum(a, b, out=c)``. Limitations From 00fbb7d9fab59a1273822d9e8881dac55edb7deb Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 01:37:59 -0800 Subject: [PATCH 08/14] Update DeprecationWarning text --- dpnp/dpnp_iface_mathematical.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index c98fdc7947a..1fbc17c831c 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -3283,8 +3283,9 @@ def maximum(*args, **kwargs): """ if len(args) >= 3 and "out" not in kwargs: warnings.warn( - "Positional `out` argument to `dpnp.maximum` is deprecated. " - "Please use the keyword form, e.g. `dpnp.maximum(a, b, out=c)`.", + "Passing more than 2 positional arguments is deprecated. If you " + "meant to use the third argument as an output, use the `out` " + "keyword argument instead.", DeprecationWarning, stacklevel=2, ) @@ -3398,8 +3399,9 @@ def minimum(*args, **kwargs): """ if len(args) >= 3 and "out" not in kwargs: warnings.warn( - "Positional `out` argument to `dpnp.minimum` is deprecated. " - "Please use the keyword form, e.g. `dpnp.minimum(a, b, out=c)`.", + "Passing more than 2 positional arguments is deprecated. If you " + "meant to use the third argument as an output, use the `out` " + "keyword argument instead.", DeprecationWarning, stacklevel=2, ) From a8932877e0dac84a626b1a940ee3b10d6ef4de9b Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 02:40:07 -0800 Subject: [PATCH 09/14] Add DPNPBinaryFuncOutKw class to handle positional out deprecation --- doc/conf.py | 9 ++++- dpnp/dpnp_algo/dpnp_elementwise_common.py | 18 ++++++++++ dpnp/dpnp_iface_mathematical.py | 42 ++--------------------- 3 files changed, 29 insertions(+), 40 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index ddc5ab552f8..32754fc0453 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -12,6 +12,7 @@ from dpnp.dpnp_algo.dpnp_elementwise_common import ( DPNPBinaryFunc, + DPNPBinaryFuncOutKw, DPNPUnaryFunc, DPNPUnaryTwoOutputsFunc, ) @@ -210,7 +211,13 @@ # -- Options for todo extension ---------------------------------------------- def _can_document_member(member, *args, **kwargs): if isinstance( - member, (DPNPBinaryFunc, DPNPUnaryFunc, DPNPUnaryTwoOutputsFunc) + member, + ( + DPNPBinaryFunc, + DPNPBinaryFuncOutKw, + DPNPUnaryFunc, + DPNPUnaryTwoOutputsFunc, + ), ): return True return orig(member, *args, **kwargs) diff --git a/dpnp/dpnp_algo/dpnp_elementwise_common.py b/dpnp/dpnp_algo/dpnp_elementwise_common.py index e2f75a92ed2..288cad0a7cc 100644 --- a/dpnp/dpnp_algo/dpnp_elementwise_common.py +++ b/dpnp/dpnp_algo/dpnp_elementwise_common.py @@ -26,6 +26,8 @@ # THE POSSIBILITY OF SUCH DAMAGE. # ***************************************************************************** +import warnings + import dpctl.tensor as dpt import dpctl.tensor._copy_utils as dtc import dpctl.tensor._tensor_impl as dti @@ -48,6 +50,7 @@ "DPNPI0", "DPNPAngle", "DPNPBinaryFunc", + "DPNPBinaryFuncOutKw", "DPNPFix", "DPNPImag", "DPNPReal", @@ -725,6 +728,21 @@ def outer( ) +class DPNPBinaryFuncOutKw(DPNPBinaryFunc): + """DPNPBinaryFunc that deprecates positional `out` argument.""" + + def __call__(self, *args, **kwargs): + if len(args) > self.nin: + warnings.warn( + "Passing more than 2 positional arguments is deprecated. " + "If you meant to use the third argument as an output, " + "use the `out` keyword argument instead.", + DeprecationWarning, + stacklevel=2, + ) + return super().__call__(*args, **kwargs) + + class DPNPAngle(DPNPUnaryFunc): """Class that implements dpnp.angle unary element-wise functions.""" diff --git a/dpnp/dpnp_iface_mathematical.py b/dpnp/dpnp_iface_mathematical.py index 1fbc17c831c..a0e2c8a329c 100644 --- a/dpnp/dpnp_iface_mathematical.py +++ b/dpnp/dpnp_iface_mathematical.py @@ -46,7 +46,6 @@ import builtins import warnings -from functools import wraps import dpctl.tensor as dpt import dpctl.tensor._tensor_elementwise_impl as ti @@ -67,6 +66,7 @@ DPNPI0, DPNPAngle, DPNPBinaryFunc, + DPNPBinaryFuncOutKw, DPNPFix, DPNPImag, DPNPReal, @@ -3266,7 +3266,7 @@ def interp(x, xp, fp, left=None, right=None, period=None): """ -_maximum_impl = DPNPBinaryFunc( +maximum = DPNPBinaryFuncOutKw( "maximum", ti._maximum_result_type, ti._maximum, @@ -3274,24 +3274,6 @@ def interp(x, xp, fp, left=None, right=None, period=None): ) -@wraps(_maximum_impl) -def maximum(*args, **kwargs): - """ - Wrapper around `_maximum_impl` that emits a DeprecationWarning - when `out` is passed positionally. - - """ - if len(args) >= 3 and "out" not in kwargs: - warnings.warn( - "Passing more than 2 positional arguments is deprecated. If you " - "meant to use the third argument as an output, use the `out` " - "keyword argument instead.", - DeprecationWarning, - stacklevel=2, - ) - return _maximum_impl(*args, **kwargs) - - _MINIMUM_DOCSTRING = """ Computes the minimum value for each element :math:`x1_i` of the input array `x1` relative to the respective element :math:`x2_i` of the input array `x2`. @@ -3382,7 +3364,7 @@ def maximum(*args, **kwargs): array(-inf) """ -_minimum_impl = DPNPBinaryFunc( +minimum = DPNPBinaryFuncOutKw( "minimum", ti._minimum_result_type, ti._minimum, @@ -3390,24 +3372,6 @@ def maximum(*args, **kwargs): ) -@wraps(_minimum_impl) -def minimum(*args, **kwargs): - """ - Wrapper around `_minimum_impl` that emits a DeprecationWarning - when `out` is passed positionally. - - """ - if len(args) >= 3 and "out" not in kwargs: - warnings.warn( - "Passing more than 2 positional arguments is deprecated. If you " - "meant to use the third argument as an output, use the `out` " - "keyword argument instead.", - DeprecationWarning, - stacklevel=2, - ) - return _minimum_impl(*args, **kwargs) - - def modf(x1, **kwargs): """ Return the fractional and integral parts of an array, element-wise. From 29494e15fd043a78cddab3af62ce0e68e0131c60 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 02:40:33 -0800 Subject: [PATCH 10/14] Update test_minimum_maximum_out_deprecated --- dpnp/tests/test_mathematical.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/dpnp/tests/test_mathematical.py b/dpnp/tests/test_mathematical.py index 2dbea16d87b..c2b49ced72c 100644 --- a/dpnp/tests/test_mathematical.py +++ b/dpnp/tests/test_mathematical.py @@ -2912,11 +2912,13 @@ def test_elemenwise_outer_scalar(): assert dpnp.allclose(result, expected) +@testing.with_requires("numpy>=2.4") +@pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize("func", ["minimum", "maximum"]) -def test_minimum_maximum_out_deprecated(func): - a = dpnp.array([1, 3, 2]) - b = dpnp.array([2, 2, 2]) - out = dpnp.empty_like(a) +def test_minimum_maximum_out_deprecated(xp, func): + a = xp.array([1, 3, 2]) + b = xp.array([2, 2, 2]) + out = xp.empty_like(a) with pytest.warns(DeprecationWarning, match="deprecated"): - _ = getattr(dpnp, func)(a, b, out) + _ = getattr(xp, func)(a, b, out) From 81b1ded02da4e609d6245daaa4299dc11dcfaf2c Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 06:39:24 -0800 Subject: [PATCH 11/14] Use wraps to restore proper signature in DPNPBinaryFuncOutKw --- dpnp/dpnp_algo/dpnp_elementwise_common.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/dpnp/dpnp_algo/dpnp_elementwise_common.py b/dpnp/dpnp_algo/dpnp_elementwise_common.py index 288cad0a7cc..11244f5c3e5 100644 --- a/dpnp/dpnp_algo/dpnp_elementwise_common.py +++ b/dpnp/dpnp_algo/dpnp_elementwise_common.py @@ -27,6 +27,7 @@ # ***************************************************************************** import warnings +from functools import wraps import dpctl.tensor as dpt import dpctl.tensor._copy_utils as dtc @@ -731,6 +732,7 @@ def outer( class DPNPBinaryFuncOutKw(DPNPBinaryFunc): """DPNPBinaryFunc that deprecates positional `out` argument.""" + @wraps(DPNPBinaryFunc.__call__) def __call__(self, *args, **kwargs): if len(args) > self.nin: warnings.warn( From a0e4d772f8e5251888854581b54488112e771b27 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 07:14:04 -0800 Subject: [PATCH 12/14] Avoid DeprecationWarning from dpnp.asfarray in tests --- dpnp/tests/test_sycl_queue.py | 5 ++++- dpnp/tests/test_usm_type.py | 5 ++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/dpnp/tests/test_sycl_queue.py b/dpnp/tests/test_sycl_queue.py index 434ec48c343..a1d927fbbde 100644 --- a/dpnp/tests/test_sycl_queue.py +++ b/dpnp/tests/test_sycl_queue.py @@ -1025,7 +1025,10 @@ def test_invalid_stream(self, stream): "asarray_chkfinite", "asanyarray", "ascontiguousarray", - "asfarray", + pytest.param( + "asfarray", + marks=pytest.mark.filterwarnings("ignore::DeprecationWarning"), + ), "asfortranarray", ], ) diff --git a/dpnp/tests/test_usm_type.py b/dpnp/tests/test_usm_type.py index 582b371e2f6..83a59fc50f2 100644 --- a/dpnp/tests/test_usm_type.py +++ b/dpnp/tests/test_usm_type.py @@ -286,7 +286,10 @@ def test_copy_operation(usm_type): "asarray_chkfinite", "asanyarray", "ascontiguousarray", - "asfarray", + pytest.param( + "asfarray", + marks=pytest.mark.filterwarnings("ignore::DeprecationWarning"), + ), "asfortranarray", ], ) From 19f08893f8b7518d16a748823e4e62d2ee3088c0 Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Tue, 11 Nov 2025 11:30:22 -0800 Subject: [PATCH 13/14] Ignore DeprecationWarning in TestBoundFuncs::test_invalid_out --- dpnp/tests/test_binary_ufuncs.py | 1 + 1 file changed, 1 insertion(+) diff --git a/dpnp/tests/test_binary_ufuncs.py b/dpnp/tests/test_binary_ufuncs.py index 782541ab41f..17e3de4c28d 100644 --- a/dpnp/tests/test_binary_ufuncs.py +++ b/dpnp/tests/test_binary_ufuncs.py @@ -175,6 +175,7 @@ def test_invalid_shape(self, func, shape): with pytest.raises(ValueError): getattr(dpnp, func)(a, b, out=out) + @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", From 7cf362866e58a0b20dfc17314a250e60df3546de Mon Sep 17 00:00:00 2001 From: Vladislav Perevezentsev Date: Wed, 12 Nov 2025 07:06:29 -0800 Subject: [PATCH 14/14] Update test_invalid_out_type to avoid DeprecationWarning --- dpnp/tests/test_binary_ufuncs.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/dpnp/tests/test_binary_ufuncs.py b/dpnp/tests/test_binary_ufuncs.py index 816dcbd1abe..0de83c5b99c 100644 --- a/dpnp/tests/test_binary_ufuncs.py +++ b/dpnp/tests/test_binary_ufuncs.py @@ -175,7 +175,6 @@ def test_invalid_shape(self, func, shape): with pytest.raises(ValueError): getattr(dpnp, func)(a, b, out=out) - @pytest.mark.filterwarnings("ignore::DeprecationWarning") @pytest.mark.parametrize("xp", [dpnp, numpy]) @pytest.mark.parametrize( "out", @@ -184,7 +183,7 @@ def test_invalid_shape(self, func, shape): ) def test_invalid_out_type(self, func, xp, out): a = xp.arange(10) - assert_raises(TypeError, getattr(xp, func), a, 2, out) + assert_raises(TypeError, getattr(xp, func), a, 2, out=out) class TestDivide: