From 00f2bbab9a2bbb7f79858539120ad1170c1d315f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Robert?= Date: Wed, 10 Jul 2024 19:42:56 +0200 Subject: [PATCH] DEPR: deprecate passing redshift (`z`) as a keyword argument (#16597) * DEPR: deprecate passing redshift (`z`) as a keyword argument Signed-off-by: nstarman Co-authored-by: nstarman --- astropy/cosmology/_signature_deprecations.c | 244 +++++++++++++++ astropy/cosmology/_utils.py | 28 +- astropy/cosmology/flrw/base.py | 296 ++++++++++++++---- astropy/cosmology/flrw/lambdacdm.py | 116 +++++-- .../cosmology/flrw/tests/test_lambdacdm.py | 32 +- astropy/cosmology/flrw/w0cdm.py | 38 ++- astropy/cosmology/flrw/w0wacdm.py | 14 +- astropy/cosmology/flrw/w0wzcdm.py | 14 +- astropy/cosmology/flrw/wpwazpcdm.py | 14 +- astropy/cosmology/setup_package.py | 28 ++ astropy/cosmology/tests/test_utils.py | 99 +++++- docs/changes/cosmology/16597.api.rst | 1 + licenses/POSITIONAL_DEFAULTS.rst | 21 ++ 13 files changed, 817 insertions(+), 128 deletions(-) create mode 100644 astropy/cosmology/_signature_deprecations.c create mode 100644 astropy/cosmology/setup_package.py create mode 100644 docs/changes/cosmology/16597.api.rst create mode 100644 licenses/POSITIONAL_DEFAULTS.rst diff --git a/astropy/cosmology/_signature_deprecations.c b/astropy/cosmology/_signature_deprecations.c new file mode 100644 index 00000000000..c4dd509d20d --- /dev/null +++ b/astropy/cosmology/_signature_deprecations.c @@ -0,0 +1,244 @@ +// This extension is adapted from the positional_defaults PyPI package +// https://pypi.org/project/positional-defaults/ version 2023.4.19 +// MIT. see licenses/POSITIONAL_DEFAULTS.rst + + +#define PY_SSIZE_T_CLEAN +#include +#include + +#define SINCE_CHAR_SIZE 32 +#define NAMES_CHAR_SIZE 128 +#define MSG_SIZE 512 + +typedef struct { + PyObject_HEAD + PyObject* dict; + PyObject* wrapped; + PyObject* names; + PyObject* since; +} DeprKwsObject; + + + +static void +depr_kws_wrap_dealloc(DeprKwsObject* self) +{ + Py_XDECREF(self->wrapped); + Py_XDECREF(self->names); + Py_XDECREF(self->since); + Py_TYPE(self)->tp_free((PyObject*)self); +} + + +static PyObject* +depr_kws_wrap_new(PyTypeObject* type, PyObject* args, PyObject* kwds) { + DeprKwsObject* self = (DeprKwsObject*)type->tp_alloc(type, 0); + + if (self != NULL) { + self->names = PyTuple_New(0); + if (self->names == NULL) { + Py_DECREF(self); + return NULL; + } + + Py_INCREF(Py_None); + self->wrapped = Py_None; + + Py_INCREF(Py_None); + self->since = Py_None; + } + + return (PyObject*)self; +} + + +static int +depr_kws_wrap_init(DeprKwsObject* self, PyObject* args, PyObject* kwds) +{ + static char *kwlist[] = {"wrapped", "names", "since", NULL}; + Py_ssize_t i, n_names; + PyObject* wrapped, *names, *since, *tmp; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "OOO:wrap", kwlist, + &wrapped, &names, &since)) + return -1; + + if (!PyTuple_Check(names)) { + PyErr_SetString(PyExc_TypeError, "names must be a tuple"); + return -1; + } + + n_names = PyTuple_GET_SIZE(names); + + for (i = 0; i < n_names; ++i) { + PyObject* name = PyTuple_GET_ITEM(names, i); + if (!PyUnicode_Check(name)) { + PyErr_Format(PyExc_TypeError, "names[%zd] must be a string", i); + return -1; + } + } + + if (!PyUnicode_Check(since)) { + PyErr_Format(PyExc_TypeError, "since must be a string", i); + return -1; + } + + tmp = self->wrapped; + Py_INCREF(wrapped); + self->wrapped = wrapped; + Py_XDECREF(tmp); + + tmp = self->names; + Py_INCREF(names); + self->names = names; + Py_XDECREF(tmp); + + tmp = self->since; + Py_INCREF(since); + self->since = since; + Py_XDECREF(tmp); + return 0; +} + + +static PyMemberDef depr_kws_wrap_members[] = { + {"__dict__", T_OBJECT, offsetof(DeprKwsObject, dict), READONLY}, + {"wrapped", T_OBJECT, offsetof(DeprKwsObject, wrapped), READONLY}, + {"names", T_OBJECT, offsetof(DeprKwsObject, names), READONLY}, + {"since", T_OBJECT, offsetof(DeprKwsObject, since), READONLY}, + {NULL} +}; + + +static PyObject* +depr_kws_wrap_call(DeprKwsObject* self, PyObject* args, PyObject* kwds) { + // step 0: return early whenever possible + if (self->wrapped == NULL) + Py_RETURN_NONE; + + if (kwds == NULL) + return PyObject_Call(self->wrapped, args, kwds); + + // step 1: detect any deprecated keyword arguments, return if none. + Py_ssize_t n_names = PyTuple_GET_SIZE(self->names); + PyObject *deprecated_kwargs = PyList_New(n_names); + Py_INCREF(deprecated_kwargs); + PyObject *name = NULL; + Py_ssize_t i = 0; + int has_kw = -2; + + Py_ssize_t n_depr = 0; + for (i=0 ; i < n_names ; ++i) { + name = PyTuple_GET_ITEM(self->names, i); + has_kw = PyDict_Contains(kwds, name); + if (has_kw) { + PyList_SET_ITEM(deprecated_kwargs, n_depr, name); + ++n_depr; + } + } + + if (n_depr == 0) + return PyObject_Call(self->wrapped, args, kwds); + + // step 2: create and emit warning message + char names_char[NAMES_CHAR_SIZE]; + char *s, *arguments, *respectively, *pronoun; + + PyObject *names_unicode; + if (n_depr > 1) { + names_unicode = PyObject_Str(PyList_GetSlice(deprecated_kwargs, 0, n_depr)); + s = "s"; + arguments = " arguments"; + respectively = ", respectively"; + pronoun = "them"; + } else { + names_unicode = PyObject_Repr(PyList_GET_ITEM(deprecated_kwargs, 0)); + s = arguments = respectively = ""; + pronoun = "it"; + } + const char* names_utf8 = PyUnicode_AsUTF8(names_unicode); + snprintf(names_char, NAMES_CHAR_SIZE, "%s", names_utf8); + + PyObject *since_unicode = PyObject_Str(self->since); + const char* since_utf8 = PyUnicode_AsUTF8(since_unicode); + char since_char[SINCE_CHAR_SIZE]; + snprintf(since_char, SINCE_CHAR_SIZE, "%s", since_utf8); + + char msg[MSG_SIZE]; + snprintf( + msg, + MSG_SIZE, + "Passing %s%s as keyword%s " + "is deprecated since version %s " + "and will stop working in a future release. " + "Pass %s positionally to suppress this warning.", + names_char, arguments, s, since_char, pronoun + ); + const char* msg_ptr = msg; + + int status = PyErr_WarnEx(PyExc_FutureWarning, msg_ptr, 2); + if (status == -1) { + // avoid leaking memory if Warning is promoted to Exception + Py_DECREF(deprecated_kwargs); + } + + return PyObject_Call(self->wrapped, args, kwds); +} + + +static PyObject* +depr_kws_wrap_get(PyObject* self, PyObject* obj, PyObject* type) { + if (obj == Py_None || obj == NULL) { + Py_INCREF(self); + return self; + } + return PyMethod_New(self, obj); +} + + +static PyTypeObject DeprKwsWrap = { + PyVarObject_HEAD_INIT(NULL, 0) + .tp_name = "_signature_deprecations.wrap", + .tp_doc = PyDoc_STR("wrap a function with deprecated keyword arguments"), + .tp_basicsize = sizeof(DeprKwsObject), + .tp_itemsize = 0, + .tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, + .tp_dictoffset = offsetof(DeprKwsObject, dict), + .tp_new = depr_kws_wrap_new, + .tp_init = (initproc)depr_kws_wrap_init, + .tp_dealloc = (destructor)depr_kws_wrap_dealloc, + .tp_members = depr_kws_wrap_members, + .tp_call = (ternaryfunc)depr_kws_wrap_call, + .tp_descr_get = depr_kws_wrap_get, +}; + + +static struct PyModuleDef module = { + PyModuleDef_HEAD_INIT, + .m_name = "_signature_deprecations", + .m_doc = PyDoc_STR("fast decorators to mark signature details as deprecated"), + .m_size = -1, +}; + + +PyMODINIT_FUNC +PyInit__signature_deprecations(void) { + PyObject* m; + + if (PyType_Ready(&DeprKwsWrap) < 0) + return NULL; + + m = PyModule_Create(&module); + if (m == NULL) + return NULL; + + Py_INCREF(&DeprKwsWrap); + if (PyModule_AddObject(m, "_depr_kws_wrap", (PyObject*)&DeprKwsWrap) < 0) { + Py_DECREF(&DeprKwsWrap); + Py_DECREF(m); + return NULL; + } + + return m; +} diff --git a/astropy/cosmology/_utils.py b/astropy/cosmology/_utils.py index e45d51370b7..84617b29e76 100644 --- a/astropy/cosmology/_utils.py +++ b/astropy/cosmology/_utils.py @@ -6,21 +6,23 @@ import functools import operator +from collections.abc import Callable from dataclasses import Field from numbers import Number -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Any, TypeVar import numpy as np from astropy.units import Quantity from . import units as cu +from ._signature_deprecations import _depr_kws_wrap if TYPE_CHECKING: - from typing import Any - from astropy.cosmology import Parameter +_F = TypeVar("_F", bound=Callable[..., Any]) + def vectorize_redshift_method(func=None, nin=1): """Vectorize a method of redshift(s). @@ -118,3 +120,23 @@ def all_parameters(obj: object, /) -> dict[str, Field | Parameter]: or (isinstance(v, Field) and isinstance(v.default, Parameter)) ) } + + +def deprecated_keywords(*kws, since): + """Deprecate calling one or more arguments as keywords. + + Parameters + ---------- + *kws: str + Names of the arguments that will become positional-only. + + since : str or number or sequence of str or number + The release at which the old argument became deprecated. + """ + return functools.partial(_depr_kws, kws=kws, since=since) + + +def _depr_kws(func: _F, /, kws: tuple[str, ...], since: str) -> _F: + wrapper = _depr_kws_wrap(func, kws, since) + functools.update_wrapper(wrapper, func) + return wrapper diff --git a/astropy/cosmology/flrw/base.py b/astropy/cosmology/flrw/base.py index ac685f46d8d..2cd7be91435 100644 --- a/astropy/cosmology/flrw/base.py +++ b/astropy/cosmology/flrw/base.py @@ -19,7 +19,11 @@ import astropy.constants as const import astropy.units as u -from astropy.cosmology._utils import aszarr, vectorize_redshift_method +from astropy.cosmology._utils import ( + aszarr, + deprecated_keywords, + vectorize_redshift_method, +) from astropy.cosmology.core import Cosmology, FlatCosmologyMixin, dataclass_decorator from astropy.cosmology.parameter import Parameter from astropy.cosmology.parameter._converter import ( @@ -84,6 +88,7 @@ def scale_factor0(self): """ return u.Quantity(self.scale_factor(0), unit=u.one) + @deprecated_keywords("z", since="7.0") def scale_factor(self, z): """Scale factor at redshift ``z``. @@ -91,9 +96,12 @@ def scale_factor(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- a : ndarray or float @@ -412,14 +420,18 @@ def Onu0(self): # --------------------------------------------------------------- @abstractmethod + @deprecated_keywords("z", since="7.0") def w(self, z): r"""The dark energy equation of state. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -437,14 +449,18 @@ def w(self, z): """ raise NotImplementedError("w(z) is not implemented") + @deprecated_keywords("z", since="7.0") def Otot(self, z): """The total density parameter at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshifts. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Otot : ndarray or float @@ -453,14 +469,18 @@ def Otot(self, z): """ return self.Om(z) + self.Ogamma(z) + self.Onu(z) + self.Ode(z) + self.Ok(z) + @deprecated_keywords("z", since="7.0") def Om(self, z): """Return the density parameter for non-relativistic matter at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Om : ndarray or float @@ -476,14 +496,18 @@ def Om(self, z): z = aszarr(z) return self._Om0 * (z + 1.0) ** 3 * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Ob(self, z): """Return the density parameter for baryonic matter at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Ob : ndarray or float @@ -501,14 +525,18 @@ def Ob(self, z): z = aszarr(z) return self._Ob0 * (z + 1.0) ** 3 * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Odm(self, z): """Return the density parameter for dark matter at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Odm : ndarray or float @@ -534,14 +562,18 @@ def Odm(self, z): z = aszarr(z) return self._Odm0 * (z + 1.0) ** 3 * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Ok(self, z): """Return the equivalent density parameter for curvature at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Ok : ndarray or float @@ -553,14 +585,18 @@ def Ok(self, z): return np.zeros(z.shape) if hasattr(z, "shape") else 0.0 return self._Ok0 * (z + 1.0) ** 2 * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Ode(self, z): """Return the density parameter for dark energy at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Ode : ndarray or float @@ -573,14 +609,18 @@ def Ode(self, z): return np.zeros(z.shape) if hasattr(z, "shape") else 0.0 return self._Ode0 * self.de_density_scale(z) * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Ogamma(self, z): """Return the density parameter for photons at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Ogamma : ndarray or float @@ -591,14 +631,18 @@ def Ogamma(self, z): z = aszarr(z) return self._Ogamma0 * (z + 1.0) ** 4 * self.inv_efunc(z) ** 2 + @deprecated_keywords("z", since="7.0") def Onu(self, z): r"""Return the density parameter for neutrinos at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Onu : ndarray or float @@ -614,14 +658,18 @@ def Onu(self, z): return np.zeros(z.shape) if hasattr(z, "shape") else 0.0 return self.Ogamma(z) * self.nu_relative_density(z) + @deprecated_keywords("z", since="7.0") def Tcmb(self, z): """Return the CMB temperature at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Tcmb : `~astropy.units.Quantity` ['temperature'] @@ -629,14 +677,18 @@ def Tcmb(self, z): """ return self._Tcmb0 * (aszarr(z) + 1.0) + @deprecated_keywords("z", since="7.0") def Tnu(self, z): """Return the neutrino temperature at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- Tnu : `~astropy.units.Quantity` ['temperature'] @@ -644,14 +696,18 @@ def Tnu(self, z): """ return self._Tnu0 * (aszarr(z) + 1.0) + @deprecated_keywords("z", since="7.0") def nu_relative_density(self, z): r"""Neutrino density function relative to the energy density in photons. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- f : ndarray or float @@ -712,15 +768,18 @@ def nu_relative_density(self, z): return prefac * self._neff_per_nu * rel_mass - def _w_integrand(self, ln1pz): + def _w_integrand(self, ln1pz, /): """Internal convenience function for w(z) integral (eq. 5 of [1]_). Parameters ---------- - ln1pz : `~numbers.Number` or scalar ndarray + ln1pz : `~numbers.Number` or scalar ndarray, positional-only Assumes scalar input, since this should only be called inside an integral. + .. versionchanged:: 7.0 + The argument is positional-only. + References ---------- .. [1] Linder, E. (2003). Exploring the Expansion History of the @@ -728,14 +787,18 @@ def _w_integrand(self, ln1pz): """ return 1.0 + self.w(exp(ln1pz) - 1.0) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float @@ -779,14 +842,18 @@ def de_density_scale(self, z): ival = quad(self._w_integrand, 0, log(z + 1.0))[0] return exp(3 * ival) + @deprecated_keywords("z", since="7.0") def efunc(self, z): """Function used to calculate H(z), the Hubble parameter. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -811,14 +878,18 @@ def efunc(self, z): + self._Ode0 * self.de_density_scale(z) ) + @deprecated_keywords("z", since="7.0") def inv_efunc(self, z): """Inverse of ``efunc``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -838,14 +909,17 @@ def inv_efunc(self, z): + self._Ode0 * self.de_density_scale(z) ) ** (-0.5) - def _lookback_time_integrand_scalar(self, z): + def _lookback_time_integrand_scalar(self, z, /): """Integrand of the lookback time (equation 30 of [1]_). Parameters ---------- - z : float + z : float, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- I : float @@ -858,14 +932,18 @@ def _lookback_time_integrand_scalar(self, z): """ return self._inv_efunc_scalar(z, *self._inv_efunc_scalar_args) / (z + 1.0) + @deprecated_keywords("z", since="7.0") def lookback_time_integrand(self, z): """Integrand of the lookback time (equation 30 of [1]_). Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : float or array @@ -879,14 +957,17 @@ def lookback_time_integrand(self, z): z = aszarr(z) return self.inv_efunc(z) / (z + 1.0) - def _abs_distance_integrand_scalar(self, z): + def _abs_distance_integrand_scalar(self, z, /): """Integrand of the absorption distance (eq. 4, [1]_). Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- dX : float @@ -898,14 +979,18 @@ def _abs_distance_integrand_scalar(self, z): """ return (z + 1.0) ** 2 * self._inv_efunc_scalar(z, *self._inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def abs_distance_integrand(self, z): """Integrand of the absorption distance (eq. 4, [1]_). Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- dX : float or array @@ -918,14 +1003,18 @@ def abs_distance_integrand(self, z): z = aszarr(z) return (z + 1.0) ** 2 * self.inv_efunc(z) + @deprecated_keywords("z", since="7.0") def H(self, z): """Hubble parameter (km/s/Mpc) at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- H : `~astropy.units.Quantity` ['frequency'] @@ -933,6 +1022,7 @@ def H(self, z): """ return self._H0 * self.efunc(z) + @deprecated_keywords("z", since="7.0") def lookback_time(self, z): """Lookback time in Gyr to redshift ``z``. @@ -941,9 +1031,12 @@ def lookback_time(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -955,7 +1048,7 @@ def lookback_time(self, z): """ return self._lookback_time(z) - def _lookback_time(self, z): + def _lookback_time(self, z, /): """Lookback time in Gyr to redshift ``z``. The lookback time is the difference between the age of the Universe now @@ -963,9 +1056,12 @@ def _lookback_time(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -982,9 +1078,12 @@ def _integral_lookback_time(self, z, /): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : float or ndarray @@ -993,6 +1092,7 @@ def _integral_lookback_time(self, z, /): """ return quad(self._lookback_time_integrand_scalar, 0, z)[0] + @deprecated_keywords("z", since="7.0") def lookback_distance(self, z): """The lookback distance is the light travel time distance to a given redshift. @@ -1002,9 +1102,12 @@ def lookback_distance(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1012,14 +1115,18 @@ def lookback_distance(self, z): """ return (self.lookback_time(z) * const.c).to(u.Mpc) + @deprecated_keywords("z", since="7.0") def age(self, z): """Age of the universe in Gyr at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -1031,16 +1138,19 @@ def age(self, z): """ return self._age(z) - def _age(self, z): + def _age(self, z, /): """Age of the universe in Gyr at redshift ``z``. This internal function exists to be re-defined for optimizations. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -1056,7 +1166,7 @@ def _integral_age(self, z, /): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. Returns @@ -1071,14 +1181,18 @@ def _integral_age(self, z, /): """ return quad(self._lookback_time_integrand_scalar, z, inf)[0] + @deprecated_keywords("z", since="7.0") def critical_density(self, z): """Critical density in grams per cubic cm at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- rho : `~astropy.units.Quantity` @@ -1086,6 +1200,7 @@ def critical_density(self, z): """ return self._critical_density0 * (self.efunc(z)) ** 2 + @deprecated_keywords("z", since="7.0") def comoving_distance(self, z): """Comoving line-of-sight distance in Mpc at a given redshift. @@ -1094,9 +1209,12 @@ def comoving_distance(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1104,7 +1222,7 @@ def comoving_distance(self, z): """ return self._comoving_distance_z1z2(0, z) - def _comoving_distance_z1z2(self, z1, z2): + def _comoving_distance_z1z2(self, z1, z2, /): """Comoving line-of-sight distance in Mpc between redshifts ``z1`` and ``z2``. The comoving distance along the line-of-sight between two objects @@ -1112,8 +1230,11 @@ def _comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` - Input redshifts. + z1, z2 : Quantity-like ['redshift'], array-like, positional-only + Input redshift. + + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. Returns ------- @@ -1131,8 +1252,11 @@ def _integral_comoving_distance_z1z2_scalar(self, z1, z2, /): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` - Input redshifts. + z1, z2 : Quantity-like ['redshift'], array-like, positional-only + Input redshift. + + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. Returns ------- @@ -1142,7 +1266,7 @@ def _integral_comoving_distance_z1z2_scalar(self, z1, z2, /): """ return quad(self._inv_efunc_scalar, z1, z2, args=self._inv_efunc_scalar_args)[0] - def _integral_comoving_distance_z1z2(self, z1, z2): + def _integral_comoving_distance_z1z2(self, z1, z2, /): """Comoving line-of-sight distance in Mpc between objects at redshifts ``z1`` and ``z2``. The comoving distance along the line-of-sight between two objects remains @@ -1150,8 +1274,11 @@ def _integral_comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'] or array-like - Input redshifts. + z1, z2 : Quantity-like ['redshift'] or array-like, positional-only + Input redshift. + + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. Returns ------- @@ -1160,6 +1287,7 @@ def _integral_comoving_distance_z1z2(self, z1, z2): """ return self._hubble_distance * self._integral_comoving_distance_z1z2_scalar(z1, z2) # fmt: skip + @deprecated_keywords("z", since="7.0") def comoving_transverse_distance(self, z): r"""Comoving transverse distance in Mpc at a given redshift. @@ -1170,9 +1298,12 @@ def comoving_transverse_distance(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1184,7 +1315,7 @@ def comoving_transverse_distance(self, z): """ return self._comoving_transverse_distance_z1z2(0, z) - def _comoving_transverse_distance_z1z2(self, z1, z2): + def _comoving_transverse_distance_z1z2(self, z1, z2, /): r"""Comoving transverse distance in Mpc between two redshifts. This value is the transverse comoving distance at redshift ``z2`` as @@ -1194,9 +1325,12 @@ def _comoving_transverse_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z1, z2 : Quantity-like ['redshift'], array-like, positional-only Input redshifts. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1217,6 +1351,7 @@ def _comoving_transverse_distance_z1z2(self, z1, z2): else: return dh / sqrtOk0 * sin(sqrtOk0 * dc.value / dh.value) + @deprecated_keywords("z", since="7.0") def angular_diameter_distance(self, z): """Angular diameter distance in Mpc at a given redshift. @@ -1226,9 +1361,12 @@ def angular_diameter_distance(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1243,6 +1381,7 @@ def angular_diameter_distance(self, z): z = aszarr(z) return self.comoving_transverse_distance(z) / (z + 1.0) + @deprecated_keywords("z", since="7.0") def luminosity_distance(self, z): """Luminosity distance in Mpc at redshift ``z``. @@ -1251,9 +1390,12 @@ def luminosity_distance(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1278,7 +1420,7 @@ def angular_diameter_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z1, z2 : Quantity-like ['redshift'], array-like Input redshifts. For most practical applications such as gravitational lensing, ``z2`` should be larger than ``z1``. The method will work for ``z2 < z1``; however, this will return @@ -1309,7 +1451,7 @@ def absorption_distance(self, z, /): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. Returns @@ -1324,6 +1466,7 @@ def absorption_distance(self, z, /): """ return quad(self._abs_distance_integrand_scalar, 0, z)[0] + @deprecated_keywords("z", since="7.0") def distmod(self, z): """Distance modulus at redshift ``z``. @@ -1332,9 +1475,12 @@ def distmod(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- distmod : `~astropy.units.Quantity` ['length'] @@ -1351,6 +1497,7 @@ def distmod(self, z): val = 5.0 * np.log10(abs(self.luminosity_distance(z).value)) + 25.0 return u.Quantity(val, u.mag) + @deprecated_keywords("z", since="7.0") def comoving_volume(self, z): r"""Comoving volume in cubic Mpc at redshift ``z``. @@ -1360,9 +1507,12 @@ def comoving_volume(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- V : `~astropy.units.Quantity` @@ -1383,6 +1533,7 @@ def comoving_volume(self, z): else: return term1 * (term2 - 1.0 / sqrt(abs(Ok0)) * np.arcsin(term3)) + @deprecated_keywords("z", since="7.0") def differential_comoving_volume(self, z): """Differential comoving volume at redshift z. @@ -1394,9 +1545,12 @@ def differential_comoving_volume(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- dV : `~astropy.units.Quantity` @@ -1406,14 +1560,18 @@ def differential_comoving_volume(self, z): dm = self.comoving_transverse_distance(z) return self._hubble_distance * (dm**2.0) / (self.efunc(z) << u.steradian) + @deprecated_keywords("z", since="7.0") def kpc_comoving_per_arcmin(self, z): """Separation in transverse comoving kpc equal to an arcmin at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1422,14 +1580,18 @@ def kpc_comoving_per_arcmin(self, z): """ return self.comoving_transverse_distance(z).to(u.kpc) / _radian_in_arcmin + @deprecated_keywords("z", since="7.0") def kpc_proper_per_arcmin(self, z): """Separation in transverse proper kpc equal to an arcminute at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -1438,14 +1600,18 @@ def kpc_proper_per_arcmin(self, z): """ return self.angular_diameter_distance(z).to(u.kpc) / _radian_in_arcmin + @deprecated_keywords("z", since="7.0") def arcsec_per_kpc_comoving(self, z): """Angular separation in arcsec equal to a comoving kpc at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- theta : `~astropy.units.Quantity` ['angle'] @@ -1454,14 +1620,18 @@ def arcsec_per_kpc_comoving(self, z): """ return _radian_in_arcsec / self.comoving_transverse_distance(z).to(u.kpc) + @deprecated_keywords("z", since="7.0") def arcsec_per_kpc_proper(self, z): """Angular separation in arcsec corresponding to a proper kpc at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- theta : `~astropy.units.Quantity` ['angle'] @@ -1533,13 +1703,17 @@ def Otot0(self): """Omega total; the total density/critical density at z=0.""" return 1.0 + @deprecated_keywords("z", since="7.0") def Otot(self, z): """The total density parameter at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` - Input redshifts. + z : Quantity-like ['redshift'], array-like + Input redshift. + + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. Returns ------- diff --git a/astropy/cosmology/flrw/lambdacdm.py b/astropy/cosmology/flrw/lambdacdm.py index 471746bfb10..61a07ba0368 100644 --- a/astropy/cosmology/flrw/lambdacdm.py +++ b/astropy/cosmology/flrw/lambdacdm.py @@ -6,7 +6,7 @@ import numpy as np from numpy import log -from astropy.cosmology._utils import aszarr +from astropy.cosmology._utils import aszarr, deprecated_keywords from astropy.cosmology.core import dataclass_decorator from astropy.utils.compat.optional_deps import HAS_SCIPY @@ -150,14 +150,18 @@ def _optimize_flat_norad(self): object.__setattr__(self, "_age", age) object.__setattr__(self, "_lookback_time", lookback_time) + @deprecated_keywords("z", since="7.0") def w(self, z): r"""Returns dark energy equation of state at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -174,14 +178,18 @@ def w(self, z): z = aszarr(z) return -1.0 * (np.ones(z.shape) if hasattr(z, "shape") else 1.0) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float @@ -196,7 +204,7 @@ def de_density_scale(self, z): z = aszarr(z) return np.ones(z.shape) if hasattr(z, "shape") else 1.0 - def _elliptic_comoving_distance_z1z2(self, z1, z2): + def _elliptic_comoving_distance_z1z2(self, z1, z2, /): r"""Comoving transverse distance in Mpc between two redshifts. This value is the transverse comoving distance at redshift ``z`` @@ -210,8 +218,11 @@ def _elliptic_comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` - Input redshifts. + z1, z2 : Quantity-like ['redshift'] or array-like, positional-only + Input redshift. + + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. Returns ------- @@ -237,7 +248,7 @@ def _elliptic_comoving_distance_z1z2(self, z1, z2): kappa = b / abs(b) if (b < 0) or (2 < b): - def phi_z(Om0, Ok0, kappa, y1, A, z): + def phi_z(Om0, Ok0, kappa, y1, A, z, /): return np.arccos( ((z + 1.0) * Om0 / abs(Ok0) + kappa * y1 - A) / ((z + 1.0) * Om0 / abs(Ok0) + kappa * y1 + A) @@ -255,7 +266,7 @@ def phi_z(Om0, Ok0, kappa, y1, A, z): # Fot the upper-left 0 self._Ode0: - def phi_z(Om0, Ok0, y1, y2, z): + def phi_z(Om0, Ok0, y1, y2, z, /): return np.arcsin(np.sqrt((y1 - y2) / ((z + 1.0) * Om0 / abs(Ok0) + y1))) yb = cos(acos(1 - b) / 3) @@ -273,7 +284,7 @@ def phi_z(Om0, Ok0, y1, y2, z): prefactor = self._hubble_distance / sqrt(abs(self._Ok0)) return prefactor * g * (ellipkinc(phi_z1, k2) - ellipkinc(phi_z2, k2)) - def _dS_comoving_distance_z1z2(self, z1, z2): + def _dS_comoving_distance_z1z2(self, z1, z2, /): r"""De Sitter comoving LoS distance in Mpc between two redshifts. The Comoving line-of-sight distance in Mpc between objects at @@ -287,9 +298,12 @@ def _dS_comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z1, z2 : Quantity-like ['redshift'] or array-like, positional-only Input redshifts. Must be 1D or scalar. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -302,7 +316,7 @@ def _dS_comoving_distance_z1z2(self, z1, z2): return self._hubble_distance * (z2 - z1) - def _EdS_comoving_distance_z1z2(self, z1, z2): + def _EdS_comoving_distance_z1z2(self, z1, z2, /): r"""Einstein-de Sitter comoving LoS distance in Mpc between two redshifts. The Comoving line-of-sight distance in Mpc between objects at @@ -317,9 +331,12 @@ def _EdS_comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z1, z2 : Quantity-like ['redshift'] or array-like, positional-only Input redshifts. Must be 1D or scalar. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -333,7 +350,7 @@ def _EdS_comoving_distance_z1z2(self, z1, z2): prefactor = 2 * self._hubble_distance return prefactor * ((z1 + 1.0) ** (-1.0 / 2) - (z2 + 1.0) ** (-1.0 / 2)) - def _hypergeometric_comoving_distance_z1z2(self, z1, z2): + def _hypergeometric_comoving_distance_z1z2(self, z1, z2, /): r"""Hypergeoemtric comoving LoS distance in Mpc between two redshifts. The Comoving line-of-sight distance in Mpc at redshifts ``z1`` and @@ -347,9 +364,12 @@ def _hypergeometric_comoving_distance_z1z2(self, z1, z2): Parameters ---------- - z1, z2 : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z1, z2 : Quantity-like ['redshift'] or array-like, positional-only Input redshifts. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- d : `~astropy.units.Quantity` ['length'] @@ -374,7 +394,7 @@ def _hypergeometric_comoving_distance_z1z2(self, z1, z2): - self._T_hypergeometric(s / (z2 + 1.0)) ) - def _T_hypergeometric(self, x): + def _T_hypergeometric(self, x, /): r"""Compute value using Gauss Hypergeometric function 2F1. .. math:: @@ -396,16 +416,19 @@ def _T_hypergeometric(self, x): """ return 2 * np.sqrt(x) * hyp2f1(1.0 / 6, 1.0 / 2, 7.0 / 6, -(x**3)) - def _dS_age(self, z): + def _dS_age(self, z, /): """Age of the universe in Gyr at redshift ``z``. The age of a de Sitter Universe is infinite. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -414,7 +437,7 @@ def _dS_age(self, z): t = inf if isinstance(z, Number) else np.full_like(z, inf, dtype=float) return self._hubble_time * t - def _EdS_age(self, z): + def _EdS_age(self, z, /): r"""Age of the universe in Gyr at redshift ``z``. For :math:`\Omega_{rad} = 0` (:math:`T_{CMB} = 0`; massless neutrinos) @@ -422,9 +445,12 @@ def _EdS_age(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -437,7 +463,7 @@ def _EdS_age(self, z): """ return (2.0 / 3) * self._hubble_time * (aszarr(z) + 1.0) ** (-1.5) - def _flat_age(self, z): + def _flat_age(self, z, /): r"""Age of the universe in Gyr at redshift ``z``. For :math:`\Omega_{rad} = 0` (:math:`T_{CMB} = 0`; massless neutrinos) @@ -445,9 +471,12 @@ def _flat_age(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -466,7 +495,7 @@ def _flat_age(self, z): ) return (prefactor * arg).real - def _EdS_lookback_time(self, z): + def _EdS_lookback_time(self, z, /): r"""Lookback time in Gyr to redshift ``z``. The lookback time is the difference between the age of the Universe now @@ -478,9 +507,12 @@ def _EdS_lookback_time(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -488,7 +520,7 @@ def _EdS_lookback_time(self, z): """ return self._EdS_age(0) - self._EdS_age(z) - def _dS_lookback_time(self, z): + def _dS_lookback_time(self, z, /): r"""Lookback time in Gyr to redshift ``z``. The lookback time is the difference between the age of the Universe now @@ -505,9 +537,12 @@ def _dS_lookback_time(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -515,7 +550,7 @@ def _dS_lookback_time(self, z): """ return self._hubble_time * log(aszarr(z) + 1.0) - def _flat_lookback_time(self, z): + def _flat_lookback_time(self, z, /): r"""Lookback time in Gyr to redshift ``z``. The lookback time is the difference between the age of the Universe now @@ -527,9 +562,12 @@ def _flat_lookback_time(self, z): Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + The argument is positional-only. + Returns ------- t : `~astropy.units.Quantity` ['time'] @@ -537,14 +575,18 @@ def _flat_lookback_time(self, z): """ return self._flat_age(0) - self._flat_age(z) + @deprecated_keywords("z", since="7.0") def efunc(self, z): """Function used to calculate H(z), the Hubble parameter. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -563,14 +605,18 @@ def efunc(self, z): return np.sqrt(zp1**2 * ((Or * zp1 + self._Om0) * zp1 + self._Ok0) + self._Ode0) + @deprecated_keywords("z", since="7.0") def inv_efunc(self, z): r"""Function used to calculate :math:`\frac{1}{H_z}`. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -682,14 +728,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def efunc(self, z): """Function used to calculate H(z), the Hubble parameter. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -708,14 +758,18 @@ def efunc(self, z): return np.sqrt(zp1**3 * (Or * zp1 + self._Om0) + self._Ode0) + @deprecated_keywords("z", since="7.0") def inv_efunc(self, z): r"""Function used to calculate :math:`\frac{1}{H_z}`. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float diff --git a/astropy/cosmology/flrw/tests/test_lambdacdm.py b/astropy/cosmology/flrw/tests/test_lambdacdm.py index 4a9033bdff0..d54611d5c98 100644 --- a/astropy/cosmology/flrw/tests/test_lambdacdm.py +++ b/astropy/cosmology/flrw/tests/test_lambdacdm.py @@ -956,16 +956,16 @@ def test_age_in_special_cosmologies(): Some analytic solutions fail at these critical points. """ c_dS = FlatLambdaCDM(100, 0, Tcmb0=0) - assert u.allclose(c_dS.age(z=0), np.inf * u.Gyr) - assert u.allclose(c_dS.age(z=1), np.inf * u.Gyr) - assert u.allclose(c_dS.lookback_time(z=0), 0 * u.Gyr) - assert u.allclose(c_dS.lookback_time(z=1), 6.777539216261741 * u.Gyr) + assert u.allclose(c_dS.age(0), np.inf * u.Gyr) + assert u.allclose(c_dS.age(1), np.inf * u.Gyr) + assert u.allclose(c_dS.lookback_time(0), 0 * u.Gyr) + assert u.allclose(c_dS.lookback_time(1), 6.777539216261741 * u.Gyr) c_EdS = FlatLambdaCDM(100, 1, Tcmb0=0) - assert u.allclose(c_EdS.age(z=0), 6.518614811154189 * u.Gyr) - assert u.allclose(c_EdS.age(z=1), 2.3046783684542738 * u.Gyr) - assert u.allclose(c_EdS.lookback_time(z=0), 0 * u.Gyr) - assert u.allclose(c_EdS.lookback_time(z=1), 4.213936442699092 * u.Gyr) + assert u.allclose(c_EdS.age(0), 6.518614811154189 * u.Gyr) + assert u.allclose(c_EdS.age(1), 2.3046783684542738 * u.Gyr) + assert u.allclose(c_EdS.lookback_time(0), 0 * u.Gyr) + assert u.allclose(c_EdS.lookback_time(1), 4.213936442699092 * u.Gyr) @pytest.mark.skipif(not HAS_SCIPY, reason="test requires scipy") @@ -975,20 +975,20 @@ def test_distance_in_special_cosmologies(): Some analytic solutions fail at these critical points. """ c_dS = FlatLambdaCDM(100, 0, Tcmb0=0) - assert u.allclose(c_dS.comoving_distance(z=0), 0 * u.Mpc) - assert u.allclose(c_dS.comoving_distance(z=1), 2997.92458 * u.Mpc) + assert u.allclose(c_dS.comoving_distance(0), 0 * u.Mpc) + assert u.allclose(c_dS.comoving_distance(1), 2997.92458 * u.Mpc) c_EdS = FlatLambdaCDM(100, 1, Tcmb0=0) - assert u.allclose(c_EdS.comoving_distance(z=0), 0 * u.Mpc) - assert u.allclose(c_EdS.comoving_distance(z=1), 1756.1435599923348 * u.Mpc) + assert u.allclose(c_EdS.comoving_distance(0), 0 * u.Mpc) + assert u.allclose(c_EdS.comoving_distance(1), 1756.1435599923348 * u.Mpc) c_dS = LambdaCDM(100, 0, 1, Tcmb0=0) - assert u.allclose(c_dS.comoving_distance(z=0), 0 * u.Mpc) - assert u.allclose(c_dS.comoving_distance(z=1), 2997.92458 * u.Mpc) + assert u.allclose(c_dS.comoving_distance(0), 0 * u.Mpc) + assert u.allclose(c_dS.comoving_distance(1), 2997.92458 * u.Mpc) c_EdS = LambdaCDM(100, 1, 0, Tcmb0=0) - assert u.allclose(c_EdS.comoving_distance(z=0), 0 * u.Mpc) - assert u.allclose(c_EdS.comoving_distance(z=1), 1756.1435599923348 * u.Mpc) + assert u.allclose(c_EdS.comoving_distance(0), 0 * u.Mpc) + assert u.allclose(c_EdS.comoving_distance(1), 1756.1435599923348 * u.Mpc) @pytest.mark.skipif(not HAS_SCIPY, reason="test requires scipy") diff --git a/astropy/cosmology/flrw/w0cdm.py b/astropy/cosmology/flrw/w0cdm.py index 3f73743d3dd..3106de640a2 100644 --- a/astropy/cosmology/flrw/w0cdm.py +++ b/astropy/cosmology/flrw/w0cdm.py @@ -5,7 +5,7 @@ import numpy as np from numpy import sqrt -from astropy.cosmology._utils import aszarr +from astropy.cosmology._utils import aszarr, deprecated_keywords from astropy.cosmology.core import dataclass_decorator from astropy.cosmology.parameter import Parameter @@ -117,14 +117,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def w(self, z): r"""Returns dark energy equation of state at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -141,14 +145,18 @@ def w(self, z): z = aszarr(z) return self._w0 * (np.ones(z.shape) if hasattr(z, "shape") else 1.0) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float @@ -163,14 +171,18 @@ def de_density_scale(self, z): """ return (aszarr(z) + 1.0) ** (3.0 * (1.0 + self._w0)) + @deprecated_keywords("z", since="7.0") def efunc(self, z): """Function used to calculate H(z), the Hubble parameter. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -190,14 +202,18 @@ def efunc(self, z): + self._Ode0 * zp1 ** (3.0 * (1.0 + self._w0)) ) + @deprecated_keywords("z", since="7.0") def inv_efunc(self, z): r"""Function used to calculate :math:`\frac{1}{H_z}`. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -313,14 +329,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def efunc(self, z): """Function used to calculate H(z), the Hubble parameter. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float @@ -339,14 +359,18 @@ def efunc(self, z): zp1**3 * (Or * zp1 + self._Om0) + self._Ode0 * zp1 ** (3.0 * (1 + self._w0)) ) + @deprecated_keywords("z", since="7.0") def inv_efunc(self, z): r"""Function used to calculate :math:`\frac{1}{H_z}`. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'], array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- E : ndarray or float diff --git a/astropy/cosmology/flrw/w0wacdm.py b/astropy/cosmology/flrw/w0wacdm.py index 16ed62719a9..b84852e7b64 100644 --- a/astropy/cosmology/flrw/w0wacdm.py +++ b/astropy/cosmology/flrw/w0wacdm.py @@ -4,7 +4,7 @@ from numpy import exp -from astropy.cosmology._utils import aszarr +from astropy.cosmology._utils import aszarr, deprecated_keywords from astropy.cosmology.core import dataclass_decorator from astropy.cosmology.parameter import Parameter @@ -141,14 +141,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def w(self, z): r"""Returns dark energy equation of state at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -166,14 +170,18 @@ def w(self, z): z = aszarr(z) return self._w0 + self._wa * z / (z + 1.0) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like, positional-only Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float diff --git a/astropy/cosmology/flrw/w0wzcdm.py b/astropy/cosmology/flrw/w0wzcdm.py index f9438cfb4ae..4d020bbecfe 100644 --- a/astropy/cosmology/flrw/w0wzcdm.py +++ b/astropy/cosmology/flrw/w0wzcdm.py @@ -4,7 +4,7 @@ from numpy import exp -from astropy.cosmology._utils import aszarr +from astropy.cosmology._utils import aszarr, deprecated_keywords from astropy.cosmology.core import dataclass_decorator from astropy.cosmology.parameter import Parameter @@ -134,14 +134,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def w(self, z): r"""Returns dark energy equation of state at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -157,14 +161,18 @@ def w(self, z): """ return self._w0 + self._wz * aszarr(z) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float diff --git a/astropy/cosmology/flrw/wpwazpcdm.py b/astropy/cosmology/flrw/wpwazpcdm.py index d4d59f13720..96fc1e26ddb 100644 --- a/astropy/cosmology/flrw/wpwazpcdm.py +++ b/astropy/cosmology/flrw/wpwazpcdm.py @@ -5,7 +5,7 @@ from numpy import exp from astropy.cosmology import units as cu -from astropy.cosmology._utils import aszarr +from astropy.cosmology._utils import aszarr, deprecated_keywords from astropy.cosmology.core import dataclass_decorator from astropy.cosmology.parameter import Parameter @@ -161,14 +161,18 @@ def __post_init__(self): object.__setattr__(self, "_inv_efunc_scalar", inv_efunc_scalar) object.__setattr__(self, "_inv_efunc_scalar_args", inv_efunc_scalar_args) + @deprecated_keywords("z", since="7.0") def w(self, z): r"""Returns dark energy equation of state at redshift ``z``. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- w : ndarray or float @@ -186,14 +190,18 @@ def w(self, z): apiv = 1.0 / (1.0 + self._zp.value) return self._wp + self._wa * (apiv - 1.0 / (aszarr(z) + 1.0)) + @deprecated_keywords("z", since="7.0") def de_density_scale(self, z): r"""Evaluates the redshift dependence of the dark energy density. Parameters ---------- - z : Quantity-like ['redshift'], array-like, or `~numbers.Number` + z : Quantity-like ['redshift'] or array-like Input redshift. + .. versionchanged:: 7.0 + Passing z as a keyword argument is deprecated. + Returns ------- I : ndarray or float diff --git a/astropy/cosmology/setup_package.py b/astropy/cosmology/setup_package.py new file mode 100644 index 00000000000..c52ed668c06 --- /dev/null +++ b/astropy/cosmology/setup_package.py @@ -0,0 +1,28 @@ +# Licensed under a 3-clause BSD style license - see LICENSE.rst + +import sys +from os.path import dirname, join, relpath + +from setuptools import Extension + +ASTROPY_COSMOLOGY_ROOT = dirname(__file__) + + +if sys.platform.startswith("win"): + # on windows, -Werror (and possibly -Wall too) isn't recognized + extra_compile_args = [] +else: + # be extra careful with this extension as it calls PyErr_WarnEx + # with a formatted message whose size cannot be determined at compile time, + # which is never done within the standard library + extra_compile_args = ["-Werror", "-Wall"] + + +def get_extensions(): + return [ + Extension( + "astropy.cosmology._signature_deprecations", + [relpath(join(ASTROPY_COSMOLOGY_ROOT, "_signature_deprecations.c"))], + extra_compile_args=extra_compile_args, + ), + ] diff --git a/astropy/cosmology/tests/test_utils.py b/astropy/cosmology/tests/test_utils.py index 48b9525d7cc..7b58592ea38 100644 --- a/astropy/cosmology/tests/test_utils.py +++ b/astropy/cosmology/tests/test_utils.py @@ -5,7 +5,12 @@ import astropy.units as u from astropy.cosmology import utils -from astropy.cosmology._utils import all_cls_vars, aszarr, vectorize_redshift_method +from astropy.cosmology._utils import ( + all_cls_vars, + aszarr, + deprecated_keywords, + vectorize_redshift_method, +) from astropy.utils.compat.optional_deps import HAS_PANDAS from astropy.utils.exceptions import AstropyDeprecationWarning @@ -112,3 +117,95 @@ class ClassB(ClassA): assert public_all_vars == {"a": 1, "b": 2, "c": 3} assert "a" not in vars(ClassB) assert "b" not in vars(ClassB) + + +class TestDeprecatedKeywords: + @classmethod + def setup_class(cls): + def noop(a, b, c, d): + # a minimal function that does nothing, + # with multiple positional-or-keywords arguments + return + + cls.base_func = noop + cls.depr_funcs = { + 1: deprecated_keywords("a", since="999.999.999")(noop), + 2: deprecated_keywords("a", "b", since="999.999.999")(noop), + 4: deprecated_keywords("a", "b", "c", "d", since="999.999.999")(noop), + } + + def test_type_safety(self): + dec = deprecated_keywords(b"a", since="999.999.999") + with pytest.raises(TypeError, match=r"names\[0\] must be a string"): + dec(self.base_func) + + dec = deprecated_keywords("a", since=b"999.999.999") + with pytest.raises(TypeError, match=r"since must be a string"): + dec(self.base_func) + + @pytest.mark.parametrize("n_deprecated_keywords", [1, 2, 4]) + def test_no_warn(self, n_deprecated_keywords): + func = self.depr_funcs[n_deprecated_keywords] + func(1, 2, 3, 4) + + @pytest.mark.parametrize( + "n_deprecated_keywords, args, kwargs, match", + [ + pytest.param( + 1, + (), + {"a": 1, "b": 2, "c": 3, "d": 4}, + r"Passing 'a' as keyword is deprecated since", + id="1 deprecation, 1 warn", + ), + pytest.param( + 2, + (1,), + {"b": 2, "c": 3, "d": 4}, + r"Passing 'b' as keyword is deprecated since", + id="2 deprecation, 1 warn", + ), + pytest.param( + 2, + (), + {"a": 1, "b": 2, "c": 3, "d": 4}, + r"Passing \['a', 'b'\] arguments as keywords is deprecated since", + id="2 deprecations, 2 warns", + ), + pytest.param( + 4, + (), + {"a": 1, "b": 2, "c": 3, "d": 4}, + ( + r"Passing \['a', 'b', 'c', 'd'\] arguments as keywords " + "is deprecated since" + ), + id="4 deprecations, 4 warns", + ), + pytest.param( + 4, + (1,), + {"b": 2, "c": 3, "d": 4}, + r"Passing \['b', 'c', 'd'\] arguments as keywords is deprecated since", + id="4 deprecations, 3 warns", + ), + pytest.param( + 4, + (1, 2), + {"c": 3, "d": 4}, + r"Passing \['c', 'd'\] arguments as keywords is deprecated since", + id="4 deprecations, 2 warns", + ), + pytest.param( + 4, + (1, 2, 3), + {"d": 4}, + r"Passing 'd' as keyword is deprecated since", + id="4 deprecations, 1 warn", + ), + ], + ) + def test_warn(self, n_deprecated_keywords, args, kwargs, match): + func = self.depr_funcs[n_deprecated_keywords] + with pytest.warns(FutureWarning, match=match): + func(*args, **kwargs) diff --git a/docs/changes/cosmology/16597.api.rst b/docs/changes/cosmology/16597.api.rst new file mode 100644 index 00000000000..b2134b8092a --- /dev/null +++ b/docs/changes/cosmology/16597.api.rst @@ -0,0 +1 @@ +Passing redshift arguments as keywords is deprecated in many methods. diff --git a/licenses/POSITIONAL_DEFAULTS.rst b/licenses/POSITIONAL_DEFAULTS.rst new file mode 100644 index 00000000000..4a5e0033755 --- /dev/null +++ b/licenses/POSITIONAL_DEFAULTS.rst @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2023 Nicolas Tessore + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file