Skip to content

Commit 319ee60

Browse files
authored
DEP: special: deprecation warning for sph_harm + comments (scipy#22167)
* DEP: Add deprecation warning for sph_harm * TST: Suppress deprecation warnings in sph_harm tests * DOC: Add deprecation removal version to sph_harm doc * TST: Add test for sph_harm deprecation warning * TST: Add comments explaining why we're testing deprecated functions
1 parent 97bd543 commit 319ee60

File tree

7 files changed

+86
-33
lines changed

7 files changed

+86
-33
lines changed

scipy/special/_special_ufuncs_docs.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5887,8 +5887,8 @@ const char *sph_harm_doc = R"(
58875887
where :math:`P_n^m` are the associated Legendre functions; see `lpmv`.
58885888
58895889
.. deprecated:: 1.15.0
5890-
This function is deprecated and will be removed in a future version.
5891-
Use `scipy.special.sph_harm_y` instead.
5890+
This function is deprecated and will be removed in SciPy 1.17.0.
5891+
Please use `scipy.special.sph_harm_y` instead.
58925892
58935893
Parameters
58945894
----------

scipy/special/tests/test_basic.py

Lines changed: 35 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4129,6 +4129,8 @@ def test_round(self):
41294129
rndrl = (10,10,10,11)
41304130
assert_array_equal(rnd,rndrl)
41314131

4132+
# sph_harm is deprecated and is implemented as a shim around sph_harm_y.
4133+
# The following two tests are maintained to verify the correctness of the shim.
41324134

41334135
def test_sph_harm():
41344136
# Tests derived from tables in
@@ -4139,35 +4141,39 @@ def test_sph_harm():
41394141
sqrt = np.sqrt
41404142
sin = np.sin
41414143
cos = np.cos
4142-
assert_array_almost_equal(sh(0,0,0,0),
4143-
0.5/sqrt(pi))
4144-
assert_array_almost_equal(sh(-2,2,0.,pi/4),
4145-
0.25*sqrt(15./(2.*pi)) *
4146-
(sin(pi/4))**2.)
4147-
assert_array_almost_equal(sh(-2,2,0.,pi/2),
4148-
0.25*sqrt(15./(2.*pi)))
4149-
assert_array_almost_equal(sh(2,2,pi,pi/2),
4150-
0.25*sqrt(15/(2.*pi)) *
4151-
exp(0+2.*pi*1j)*sin(pi/2.)**2.)
4152-
assert_array_almost_equal(sh(2,4,pi/4.,pi/3.),
4153-
(3./8.)*sqrt(5./(2.*pi)) *
4154-
exp(0+2.*pi/4.*1j) *
4155-
sin(pi/3.)**2. *
4156-
(7.*cos(pi/3.)**2.-1))
4157-
assert_array_almost_equal(sh(4,4,pi/8.,pi/6.),
4158-
(3./16.)*sqrt(35./(2.*pi)) *
4159-
exp(0+4.*pi/8.*1j)*sin(pi/6.)**4.)
4144+
with suppress_warnings() as sup:
4145+
sup.filter(category=DeprecationWarning)
4146+
assert_array_almost_equal(sh(0,0,0,0),
4147+
0.5/sqrt(pi))
4148+
assert_array_almost_equal(sh(-2,2,0.,pi/4),
4149+
0.25*sqrt(15./(2.*pi)) *
4150+
(sin(pi/4))**2.)
4151+
assert_array_almost_equal(sh(-2,2,0.,pi/2),
4152+
0.25*sqrt(15./(2.*pi)))
4153+
assert_array_almost_equal(sh(2,2,pi,pi/2),
4154+
0.25*sqrt(15/(2.*pi)) *
4155+
exp(0+2.*pi*1j)*sin(pi/2.)**2.)
4156+
assert_array_almost_equal(sh(2,4,pi/4.,pi/3.),
4157+
(3./8.)*sqrt(5./(2.*pi)) *
4158+
exp(0+2.*pi/4.*1j) *
4159+
sin(pi/3.)**2. *
4160+
(7.*cos(pi/3.)**2.-1))
4161+
assert_array_almost_equal(sh(4,4,pi/8.,pi/6.),
4162+
(3./16.)*sqrt(35./(2.*pi)) *
4163+
exp(0+4.*pi/8.*1j)*sin(pi/6.)**4.)
41604164

41614165

41624166
def test_sph_harm_ufunc_loop_selection():
41634167
# see https://github.com/scipy/scipy/issues/4895
41644168
dt = np.dtype(np.complex128)
4165-
assert_equal(special.sph_harm(0, 0, 0, 0).dtype, dt)
4166-
assert_equal(special.sph_harm([0], 0, 0, 0).dtype, dt)
4167-
assert_equal(special.sph_harm(0, [0], 0, 0).dtype, dt)
4168-
assert_equal(special.sph_harm(0, 0, [0], 0).dtype, dt)
4169-
assert_equal(special.sph_harm(0, 0, 0, [0]).dtype, dt)
4170-
assert_equal(special.sph_harm([0], [0], [0], [0]).dtype, dt)
4169+
with suppress_warnings() as sup:
4170+
sup.filter(category=DeprecationWarning)
4171+
assert_equal(special.sph_harm(0, 0, 0, 0).dtype, dt)
4172+
assert_equal(special.sph_harm([0], 0, 0, 0).dtype, dt)
4173+
assert_equal(special.sph_harm(0, [0], 0, 0).dtype, dt)
4174+
assert_equal(special.sph_harm(0, 0, [0], 0).dtype, dt)
4175+
assert_equal(special.sph_harm(0, 0, 0, [0]).dtype, dt)
4176+
assert_equal(special.sph_harm([0], [0], [0], [0]).dtype, dt)
41714177

41724178

41734179
class TestStruve:
@@ -4667,3 +4673,8 @@ def test_warn_xlpmn(self, xlpmn):
46674673
message = f"`scipy.special.{xlpmn.__name__}` is deprecated..."
46684674
with pytest.deprecated_call(match=message):
46694675
_ = xlpmn(1, 1, 0)
4676+
4677+
def test_warn_sph_harm(self):
4678+
msg = "`scipy.special.sph_harm` is deprecated..."
4679+
with pytest.deprecated_call(match=msg):
4680+
_ = special.sph_harm(1, 1, 0, 0)

scipy/special/tests/test_data.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,15 @@ def data_local(func, dataname, *a, **kw):
5656
return FuncData(func, DATASETS_LOCAL[dataname], *a, **kw)
5757

5858

59+
# The functions lpn, lpmn, clpmn, and sph_harm appearing below are
60+
# deprecated in favor of legendre_p_all, assoc_legendre_p_all,
61+
# assoc_legendre_p_all (assoc_legendre_p_all covers lpmn and clpmn),
62+
# and sph_harm_y respectively. The deprecated functions listed above are
63+
# implemented as shims around their respective replacements. The replacements
64+
# are tested separately, but tests for the deprecated functions remain to
65+
# verify the correctness of the shims.
66+
67+
5968
def ellipk_(k):
6069
return ellipk(k*k)
6170

@@ -191,7 +200,9 @@ def spherical_yn_(n, x):
191200
return spherical_yn(n.astype('l'), x)
192201

193202
def sph_harm_(m, n, theta, phi):
194-
y = sph_harm(m, n, theta, phi)
203+
with suppress_warnings() as sup:
204+
sup.filter(category=DeprecationWarning)
205+
y = sph_harm(m, n, theta, phi)
195206
return (y.real, y.imag)
196207

197208
def cexpm1(x, y):

scipy/special/tests/test_legendre.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,14 @@
1010
from scipy.special import (legendre_p, legendre_p_all, assoc_legendre_p,
1111
assoc_legendre_p_all, sph_legendre_p, sph_legendre_p_all)
1212

13+
# The functions lpn, lpmn, clpmn, appearing below are
14+
# deprecated in favor of legendre_p_all, assoc_legendre_p_all, and
15+
# assoc_legendre_p_all (assoc_legendre_p_all covers lpmn and clpmn)
16+
# respectively. The deprecated functions listed above are implemented as
17+
# shims around their respective replacements. The replacements are tested
18+
# separately, but tests for the deprecated functions remain to verify the
19+
# correctness of the shims.
20+
1321
# Base polynomials come from Abrahmowitz and Stegan
1422
class TestLegendre:
1523
def test_legendre(self):

scipy/special/tests/test_mpmath.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -671,6 +671,14 @@ def test_lambertw_smallz():
671671
# Systematic tests
672672
# ------------------------------------------------------------------------------
673673

674+
# The functions lpn, lpmn, clpmn, and sph_harm appearing below are
675+
# deprecated in favor of legendre_p_all, assoc_legendre_p_all,
676+
# assoc_legendre_p_all (assoc_legendre_p_all covers lpmn and clpmn),
677+
# and sph_harm_y respectively. The deprecated functions listed above are
678+
# implemented as shims around their respective replacements. The replacements
679+
# are tested separately, but tests for the deprecated functions remain to
680+
# verify the correctness of the shims.
681+
674682
HYPERKW = dict(maxprec=200, maxterms=200)
675683

676684

@@ -2015,7 +2023,9 @@ def test_spherharm(self):
20152023
def spherharm(l, m, theta, phi):
20162024
if m > l:
20172025
return np.nan
2018-
return sc.sph_harm(m, l, phi, theta)
2026+
with suppress_warnings() as sup:
2027+
sup.filter(category=DeprecationWarning)
2028+
return sc.sph_harm(m, l, phi, theta)
20192029
assert_mpmath_equal(
20202030
spherharm,
20212031
mpmath.spherharm,

scipy/special/tests/test_sph_harm.py

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import numpy as np
22
import pytest
33

4-
from numpy.testing import assert_allclose
4+
from numpy.testing import assert_allclose, suppress_warnings
55
import scipy.special as sc
66

77
class TestSphHarm:
@@ -53,6 +53,9 @@ def test_first_harmonics():
5353
# `phi` as the polar angle, and include the Condon-Shortley
5454
# phase.
5555

56+
# sph_harm is deprecated and is implemented as a shim around sph_harm_y.
57+
# This test is maintained to verify the correctness of the shim.
58+
5659
# Notation is Ymn
5760
def Y00(theta, phi):
5861
return 0.5*np.sqrt(1/np.pi)
@@ -75,7 +78,9 @@ def Y11(theta, phi):
7578
theta, phi = np.meshgrid(theta, phi)
7679

7780
for harm, m, n in zip(harms, m, n):
78-
assert_allclose(sc.sph_harm(m, n, theta, phi),
79-
harm(theta, phi),
80-
rtol=1e-15, atol=1e-15,
81-
err_msg=f"Y^{m}_{n} incorrect")
81+
with suppress_warnings() as sup:
82+
sup.filter(category=DeprecationWarning)
83+
assert_allclose(sc.sph_harm(m, n, theta, phi),
84+
harm(theta, phi),
85+
rtol=1e-15, atol=1e-15,
86+
err_msg=f"Y^{m}_{n} incorrect")

scipy/special/xsf_special.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,14 @@ namespace {
1313

1414
template <typename T>
1515
std::complex<T> sph_harm(long long int m, long long int n, T theta, T phi) {
16+
PyGILState_STATE gstate = PyGILState_Ensure();
17+
PyErr_WarnEx(
18+
PyExc_DeprecationWarning,
19+
"`scipy.special.sph_harm` is deprecated as of SciPy 1.15.0 and will be "
20+
"removed in SciPy 1.17.0. Please use `scipy.special.sph_harm_y` instead.",
21+
1
22+
);
23+
PyGILState_Release(gstate);
1624
if (n < 0) {
1725
xsf::set_error("sph_harm", SF_ERROR_ARG, "n should not be negative");
1826
return std::numeric_limits<T>::quiet_NaN();

0 commit comments

Comments
 (0)