Merge pull request #21617 from charris/update-download-wheels
MAINT, STY: Make download-wheels download source files.
diff --git a/.github/workflows/build_test.yml b/.github/workflows/build_test.yml
index dd4dff0..4a2e3e6 100644
--- a/.github/workflows/build_test.yml
+++ b/.github/workflows/build_test.yml
@@ -250,10 +250,12 @@
# use x86_64 cross-compiler to speed up the build
sudo apt update
sudo apt install -y gcc-arm-linux-gnueabihf g++-arm-linux-gnueabihf
+
+ # Keep the `test_requirements.txt` dependency-subset synced
docker run --name the_container --interactive -v /:/host arm32v7/ubuntu:focal /bin/bash -c "
apt update &&
apt install -y git python3 python3-dev python3-pip &&
- pip3 install cython==0.29.30 setuptools\<49.2.0 hypothesis==6.23.3 pytest==6.2.5 &&
+ pip3 install cython==0.29.30 setuptools\<49.2.0 hypothesis==6.23.3 pytest==6.2.5 'typing_extensions>=4.2.0' &&
ln -s /host/lib64 /lib64 &&
ln -s /host/lib/x86_64-linux-gnu /lib/x86_64-linux-gnu &&
ln -s /host/usr/arm-linux-gnueabihf /usr/arm-linux-gnueabihf &&
diff --git a/environment.yml b/environment.yml
index c45b406..24bf738 100644
--- a/environment.yml
+++ b/environment.yml
@@ -20,6 +20,7 @@
- hypothesis
# For type annotations
- mypy=0.950
+ - typing_extensions>=4.2.0
# For building docs
- sphinx=4.5.0
- sphinx-panels
diff --git a/numpy/_typing/_generic_alias.py b/numpy/_typing/_generic_alias.py
index 0541ad7..d32814a 100644
--- a/numpy/_typing/_generic_alias.py
+++ b/numpy/_typing/_generic_alias.py
@@ -64,7 +64,7 @@
args.append(value)
cls = type(alias)
- return cls(alias.__origin__, tuple(args))
+ return cls(alias.__origin__, tuple(args), alias.__unpacked__)
class _GenericAlias:
@@ -80,7 +80,14 @@
"""
- __slots__ = ("__weakref__", "_origin", "_args", "_parameters", "_hash")
+ __slots__ = (
+ "__weakref__",
+ "_origin",
+ "_args",
+ "_parameters",
+ "_hash",
+ "_starred",
+ )
@property
def __origin__(self) -> type:
@@ -95,14 +102,27 @@
"""Type variables in the ``GenericAlias``."""
return super().__getattribute__("_parameters")
+ @property
+ def __unpacked__(self) -> bool:
+ return super().__getattribute__("_starred")
+
+ @property
+ def __typing_unpacked_tuple_args__(self) -> tuple[object, ...] | None:
+ # NOTE: This should return `__args__` if `__origin__` is a tuple,
+ # which should never be the case with how `_GenericAlias` is used
+ # within numpy
+ return None
+
def __init__(
self,
origin: type,
args: object | tuple[object, ...],
+ starred: bool = False,
) -> None:
self._origin = origin
self._args = args if isinstance(args, tuple) else (args,)
self._parameters = tuple(_parse_parameters(self.__args__))
+ self._starred = starred
@property
def __call__(self) -> type[Any]:
@@ -110,10 +130,10 @@
def __reduce__(self: _T) -> tuple[
type[_T],
- tuple[type[Any], tuple[object, ...]],
+ tuple[type[Any], tuple[object, ...], bool],
]:
cls = type(self)
- return cls, (self.__origin__, self.__args__)
+ return cls, (self.__origin__, self.__args__, self.__unpacked__)
def __mro_entries__(self, bases: Iterable[object]) -> tuple[type[Any]]:
return (self.__origin__,)
@@ -130,7 +150,11 @@
try:
return super().__getattribute__("_hash")
except AttributeError:
- self._hash: int = hash(self.__origin__) ^ hash(self.__args__)
+ self._hash: int = (
+ hash(self.__origin__) ^
+ hash(self.__args__) ^
+ hash(self.__unpacked__)
+ )
return super().__getattribute__("_hash")
def __instancecheck__(self, obj: object) -> NoReturn:
@@ -147,7 +171,8 @@
"""Return ``repr(self)``."""
args = ", ".join(_to_str(i) for i in self.__args__)
origin = _to_str(self.__origin__)
- return f"{origin}[{args}]"
+ prefix = "*" if self.__unpacked__ else ""
+ return f"{prefix}{origin}[{args}]"
def __getitem__(self: _T, key: object | tuple[object, ...]) -> _T:
"""Return ``self[key]``."""
@@ -169,9 +194,17 @@
return NotImplemented
return (
self.__origin__ == value.__origin__ and
- self.__args__ == value.__args__
+ self.__args__ == value.__args__ and
+ self.__unpacked__ == getattr(
+ value, "__unpacked__", self.__unpacked__
+ )
)
+ def __iter__(self: _T) -> Generator[_T, None, None]:
+ """Return ``iter(self)``."""
+ cls = type(self)
+ yield cls(self.__origin__, self.__args__, True)
+
_ATTR_EXCEPTIONS: ClassVar[frozenset[str]] = frozenset({
"__origin__",
"__args__",
@@ -181,6 +214,8 @@
"__reduce_ex__",
"__copy__",
"__deepcopy__",
+ "__unpacked__",
+ "__typing_unpacked_tuple_args__",
})
def __getattribute__(self, name: str) -> Any:
diff --git a/numpy/core/include/numpy/numpyconfig.h b/numpy/core/include/numpy/numpyconfig.h
index b2e7c45..6be87b7 100644
--- a/numpy/core/include/numpy/numpyconfig.h
+++ b/numpy/core/include/numpy/numpyconfig.h
@@ -63,6 +63,7 @@
#define NPY_1_20_API_VERSION 0x0000000e
#define NPY_1_21_API_VERSION 0x0000000e
#define NPY_1_22_API_VERSION 0x0000000f
-#define NPY_1_23_API_VERSION 0x0000000f
+#define NPY_1_23_API_VERSION 0x00000010
+#define NPY_1_24_API_VERSION 0x00000010
#endif /* NUMPY_CORE_INCLUDE_NUMPY_NPY_NUMPYCONFIG_H_ */
diff --git a/numpy/core/setup.py b/numpy/core/setup.py
index fe90201..41f702b 100644
--- a/numpy/core/setup.py
+++ b/numpy/core/setup.py
@@ -476,11 +476,8 @@
local_dir = config.local_path
codegen_dir = join(local_dir, 'code_generators')
- if is_released:
- warnings.simplefilter('error', MismatchCAPIWarning)
-
# Check whether we have a mismatch between the set C API VERSION and the
- # actual C API VERSION
+ # actual C API VERSION. Will raise a MismatchCAPIError if so.
check_api_version(C_API_VERSION, codegen_dir)
generate_umath_py = join(codegen_dir, 'generate_umath.py')
diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py
index 44fa0a6..27281fd 100644
--- a/numpy/core/setup_common.py
+++ b/numpy/core/setup_common.py
@@ -31,6 +31,8 @@
# (*not* C_ABI_VERSION) would be increased. Whenever binary compatibility is
# broken, both C_API_VERSION and C_ABI_VERSION should be increased.
#
+# The version needs to be kept in sync with that in cversions.txt.
+#
# 0x00000008 - 1.7.x
# 0x00000009 - 1.8.x
# 0x00000009 - 1.9.x
@@ -45,10 +47,11 @@
# 0x0000000e - 1.20.x
# 0x0000000e - 1.21.x
# 0x0000000f - 1.22.x
-# 0x0000000f - 1.23.x
-C_API_VERSION = 0x0000000f
+# 0x00000010 - 1.23.x
+# 0x00000010 - 1.24.x
+C_API_VERSION = 0x00000010
-class MismatchCAPIWarning(Warning):
+class MismatchCAPIError(ValueError):
pass
@@ -84,14 +87,13 @@
# To compute the checksum of the current API, use numpy/core/cversions.py
if not curapi_hash == api_hash:
msg = ("API mismatch detected, the C API version "
- "numbers have to be updated. Current C api version is %d, "
- "with checksum %s, but recorded checksum for C API version %d "
- "in core/codegen_dir/cversions.txt is %s. If functions were "
- "added in the C API, you have to update C_API_VERSION in %s."
+ "numbers have to be updated. Current C api version is "
+ f"{apiversion}, with checksum {curapi_hash}, but recorded "
+ f"checksum in core/codegen_dir/cversions.txt is {api_hash}. If "
+ "functions were added in the C API, you have to update "
+ f"C_API_VERSION in {__file__}."
)
- warnings.warn(msg % (apiversion, curapi_hash, apiversion, api_hash,
- __file__),
- MismatchCAPIWarning, stacklevel=2)
+ raise MismatchCAPIError(msg)
FUNC_CALL_ARGS = {}
diff --git a/numpy/core/src/multiarray/alloc.c b/numpy/core/src/multiarray/alloc.c
index 6f18054..8b765aa 100644
--- a/numpy/core/src/multiarray/alloc.c
+++ b/numpy/core/src/multiarray/alloc.c
@@ -424,10 +424,7 @@
};
/* singleton capsule of the default handler */
PyObject *PyDataMem_DefaultHandler;
-
-#if (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x07030600)
PyObject *current_handler;
-#endif
int uo_index=0; /* user_override index */
@@ -539,7 +536,6 @@
PyDataMem_SetHandler(PyObject *handler)
{
PyObject *old_handler;
-#if (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x07030600)
PyObject *token;
if (PyContextVar_Get(current_handler, NULL, &old_handler)) {
return NULL;
@@ -554,27 +550,6 @@
}
Py_DECREF(token);
return old_handler;
-#else
- PyObject *p;
- p = PyThreadState_GetDict();
- if (p == NULL) {
- return NULL;
- }
- old_handler = PyDict_GetItemString(p, "current_allocator");
- if (old_handler == NULL) {
- old_handler = PyDataMem_DefaultHandler
- }
- Py_INCREF(old_handler);
- if (handler == NULL) {
- handler = PyDataMem_DefaultHandler;
- }
- const int error = PyDict_SetItemString(p, "current_allocator", handler);
- if (error) {
- Py_DECREF(old_handler);
- return NULL;
- }
- return old_handler;
-#endif
}
/*NUMPY_API
@@ -585,28 +560,10 @@
PyDataMem_GetHandler()
{
PyObject *handler;
-#if (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x07030600)
if (PyContextVar_Get(current_handler, NULL, &handler)) {
return NULL;
}
return handler;
-#else
- PyObject *p = PyThreadState_GetDict();
- if (p == NULL) {
- return NULL;
- }
- handler = PyDict_GetItem(p, npy_ma_str_current_allocator);
- if (handler == NULL) {
- handler = PyCapsule_New(&default_handler, "mem_handler", NULL);
- if (handler == NULL) {
- return NULL;
- }
- }
- else {
- Py_INCREF(handler);
- }
- return handler;
-#endif
}
NPY_NO_EXPORT PyObject *
diff --git a/numpy/core/src/multiarray/alloc.h b/numpy/core/src/multiarray/alloc.h
index e82f2d9..0f5a752 100644
--- a/numpy/core/src/multiarray/alloc.h
+++ b/numpy/core/src/multiarray/alloc.h
@@ -44,9 +44,7 @@
}
extern PyDataMem_Handler default_handler;
-#if (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x07030600)
extern PyObject *current_handler; /* PyContextVar/PyCapsule */
-#endif
NPY_NO_EXPORT PyObject *
get_handler_name(PyObject *NPY_UNUSED(self), PyObject *obj);
diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c
index 5853e06..d898a35 100644
--- a/numpy/core/src/multiarray/compiled_base.c
+++ b/numpy/core/src/multiarray/compiled_base.c
@@ -1393,11 +1393,7 @@
{
PyObject *obj;
PyObject *str;
- #if !defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM > 0x07030300
const char *docstr;
- #else
- char *docstr;
- #endif
static char *msg = "already has a different docstring";
/* Don't add docstrings */
diff --git a/numpy/core/src/multiarray/multiarraymodule.c b/numpy/core/src/multiarray/multiarraymodule.c
index ce47276..5209d69 100644
--- a/numpy/core/src/multiarray/multiarraymodule.c
+++ b/numpy/core/src/multiarray/multiarraymodule.c
@@ -4997,16 +4997,15 @@
if (PyDataMem_DefaultHandler == NULL) {
goto err;
}
-#if (!defined(PYPY_VERSION_NUM) || PYPY_VERSION_NUM >= 0x07030600)
/*
* Initialize the context-local current handler
* with the default PyDataMem_Handler capsule.
- */
+ */
current_handler = PyContextVar_New("current_allocator", PyDataMem_DefaultHandler);
if (current_handler == NULL) {
goto err;
}
-#endif
+
return m;
err:
diff --git a/numpy/core/src/multiarray/typeinfo.c b/numpy/core/src/multiarray/typeinfo.c
index 8cf6bc1..18179f7 100644
--- a/numpy/core/src/multiarray/typeinfo.c
+++ b/numpy/core/src/multiarray/typeinfo.c
@@ -9,12 +9,6 @@
#include "npy_pycompat.h"
#include "typeinfo.h"
-#if (defined(PYPY_VERSION_NUM) && (PYPY_VERSION_NUM <= 0x07030000))
-/* PyPy issue 3160 */
-#include <structseq.h>
-#endif
-
-
static PyTypeObject PyArray_typeinfoType;
static PyTypeObject PyArray_typeinforangedType;
@@ -99,17 +93,6 @@
return entry;
}
-/* Python version needed for older PyPy */
-#if (defined(PYPY_VERSION_NUM) && (PYPY_VERSION_NUM < 0x07020000))
- static int
- PyStructSequence_InitType2(PyTypeObject *type, PyStructSequence_Desc *desc) {
- PyStructSequence_InitType(type, desc);
- if (PyErr_Occurred()) {
- return -1;
- }
- return 0;
- }
-#endif
NPY_NO_EXPORT int
typeinfo_init_structsequences(PyObject *multiarray_dict)
diff --git a/numpy/typing/tests/test_generic_alias.py b/numpy/typing/tests/test_generic_alias.py
index ae55ef4..093e121 100644
--- a/numpy/typing/tests/test_generic_alias.py
+++ b/numpy/typing/tests/test_generic_alias.py
@@ -10,6 +10,7 @@
import pytest
import numpy as np
from numpy._typing._generic_alias import _GenericAlias
+from typing_extensions import Unpack
ScalarType = TypeVar("ScalarType", bound=np.generic, covariant=True)
T1 = TypeVar("T1")
@@ -55,8 +56,6 @@
("__origin__", lambda n: n.__origin__),
("__args__", lambda n: n.__args__),
("__parameters__", lambda n: n.__parameters__),
- ("__reduce__", lambda n: n.__reduce__()[1:]),
- ("__reduce_ex__", lambda n: n.__reduce_ex__(1)[1:]),
("__mro_entries__", lambda n: n.__mro_entries__([object])),
("__hash__", lambda n: hash(n)),
("__repr__", lambda n: repr(n)),
@@ -66,7 +65,6 @@
("__getitem__", lambda n: n[Union[T1, T2]][np.float32, np.float64]),
("__eq__", lambda n: n == n),
("__ne__", lambda n: n != np.ndarray),
- ("__dir__", lambda n: dir(n)),
("__call__", lambda n: n((1,), np.int64, BUFFER)),
("__call__", lambda n: n(shape=(1,), dtype=np.int64, buffer=BUFFER)),
("subclassing", lambda n: _get_subclass_mro(n)),
@@ -100,6 +98,45 @@
value_ref = func(NDArray_ref)
assert value == value_ref
+ def test_dir(self) -> None:
+ value = dir(NDArray)
+ if sys.version_info < (3, 9):
+ return
+
+ # A number attributes only exist in `types.GenericAlias` in >= 3.11
+ if sys.version_info < (3, 11, 0, "beta", 3):
+ value.remove("__typing_unpacked_tuple_args__")
+ if sys.version_info < (3, 11, 0, "beta", 1):
+ value.remove("__unpacked__")
+ assert value == dir(NDArray_ref)
+
+ @pytest.mark.parametrize("name,func,dev_version", [
+ ("__iter__", lambda n: len(list(n)), ("beta", 1)),
+ ("__iter__", lambda n: next(iter(n)), ("beta", 1)),
+ ("__unpacked__", lambda n: n.__unpacked__, ("beta", 1)),
+ ("Unpack", lambda n: Unpack[n], ("beta", 1)),
+
+ # The right operand should now have `__unpacked__ = True`,
+ # and they are thus now longer equivalent
+ ("__ne__", lambda n: n != next(iter(n)), ("beta", 1)),
+
+ # >= beta3 stuff
+ ("__typing_unpacked_tuple_args__",
+ lambda n: n.__typing_unpacked_tuple_args__, ("beta", 3)),
+ ])
+ def test_py311_features(
+ self,
+ name: str,
+ func: FuncType,
+ dev_version: tuple[str, int],
+ ) -> None:
+ """Test Python 3.11 features."""
+ value = func(NDArray)
+
+ if sys.version_info >= (3, 11, 0, *dev_version):
+ value_ref = func(NDArray_ref)
+ assert value == value_ref
+
def test_weakref(self) -> None:
"""Test ``__weakref__``."""
value = weakref.ref(NDArray)()
diff --git a/test_requirements.txt b/test_requirements.txt
index ff39dbc..c5fec8c 100644
--- a/test_requirements.txt
+++ b/test_requirements.txt
@@ -11,3 +11,4 @@
# - Mypy relies on C API features not present in PyPy
# NOTE: Keep mypy in sync with environment.yml
mypy==0.950; platform_python_implementation != "PyPy"
+typing_extensions>=4.2.0