diff options
| author | Pamphile ROY <roy.pamphile@gmail.com> | 2021-04-16 18:40:33 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-04-16 18:40:33 +0200 |
| commit | 2ba1cdedf8a8ee68cf6c0273e98c7fc2ed7f47cf (patch) | |
| tree | 2c282c939d25d0a5991ca32085161e90fb33f023 | |
| parent | f47f64e319faca16519fb2a229b4ebb5c0271850 (diff) | |
| parent | a6cd7b4f56c9fbffb9e72e8ffc5a0b9e70d1b06d (diff) | |
| download | numpy-2ba1cdedf8a8ee68cf6c0273e98c7fc2ed7f47cf.tar.gz | |
Merge branch 'main' into test_guidelines_random_asserts
| -rw-r--r-- | doc/TESTS.rst.txt | 18 | ||||
| -rw-r--r-- | doc/source/conf.py | 1 | ||||
| -rw-r--r-- | numpy/__init__.pyi | 156 | ||||
| -rw-r--r-- | numpy/fft/__init__.py | 4 | ||||
| -rw-r--r-- | numpy/fft/__init__.pyi | 4 | ||||
| -rw-r--r-- | numpy/linalg/__init__.py | 3 | ||||
| -rw-r--r-- | numpy/linalg/__init__.pyi | 4 | ||||
| -rw-r--r-- | numpy/polynomial/__init__.py | 16 | ||||
| -rw-r--r-- | numpy/polynomial/__init__.pyi | 4 | ||||
| -rw-r--r-- | numpy/random/_generator.pyx | 2 | ||||
| -rw-r--r-- | numpy/typing/_shape.py | 11 | ||||
| -rw-r--r-- | numpy/typing/tests/data/pass/array_constructors.py | 16 |
12 files changed, 177 insertions, 62 deletions
diff --git a/doc/TESTS.rst.txt b/doc/TESTS.rst.txt index fd8845291..ba09aa800 100644 --- a/doc/TESTS.rst.txt +++ b/doc/TESTS.rst.txt @@ -106,6 +106,8 @@ module called ``test_yyy.py``. If you only need to test one aspect of More often, we need to group a number of tests together, so we create a test class:: + import pytest + # import xxx symbols from numpy.xxx.yyy import zzz import pytest @@ -115,11 +117,23 @@ a test class:: assert zzz() == 'Hello from zzz' def test_invalid_parameter(self): - with pytest.raises(xxxError, match='expected error message'): + with pytest.raises(ValueError, match='.*some matching regex.*'): ... Within these test methods, ``assert`` and related functions are used to test whether a certain assumption is valid. If the assertion fails, the test fails. +``pytest`` internally rewrites the ``assert`` statement to give informative +output when it fails, so should be preferred over the legacy variant +``numpy.testing.assert_``. Whereas plain ``assert`` statements are ignored +when running Python in optimized mode with ``-O``, this is not an issue when +running tests with pytest. + +Similarly, the pytest functions :func:`pytest.raises` and :func:`pytest.warns` +should be preferred over their legacy counterparts +:func:`numpy.testing.assert_raises` and :func:`numpy.testing.assert_warns`, +since the pytest variants are more broadly used and allow more explicit +targeting of warnings and errors when used with the ``match`` regex. + Note that ``test_`` functions or methods should not have a docstring, because that makes it hard to identify the test from the output of running the test @@ -185,7 +199,7 @@ Parametric tests One very nice feature of testing is allowing easy testing across a range of parameters - a nasty problem for standard unit tests. Use the -``dec.paramaterize`` decorator. +``pytest.mark.parametrize`` decorator. Doctests -------- diff --git a/doc/source/conf.py b/doc/source/conf.py index 95865c024..fdb9f926d 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -292,6 +292,7 @@ intersphinx_mapping = { 'skimage': ('https://scikit-image.org/docs/stable', None), 'pandas': ('https://pandas.pydata.org/pandas-docs/stable', None), 'scipy-lecture-notes': ('https://scipy-lectures.org', None), + 'pytest': ('https://docs.pytest.org/en/stable', None), } diff --git a/numpy/__init__.pyi b/numpy/__init__.pyi index 8565d4b40..f3b331d50 100644 --- a/numpy/__init__.pyi +++ b/numpy/__init__.pyi @@ -368,26 +368,58 @@ __git_version__: str # TODO: Move placeholders to their respective module once # their annotations are properly implemented # -# Placeholders for non-functions (types and other objects) -DataSource: Type[Any] -MachAr: Type[Any] +# Placeholders for classes +# TODO: Remove the `__getattr__` methods once the classes are stubbed out +class DataSource: + def __getattr__(self, key: str) -> Any: ... + +class MachAr: + def __getattr__(self, key: str) -> Any: ... + +class broadcast: + def __getattr__(self, key: str) -> Any: ... + +class busdaycalendar: + def __getattr__(self, key: str) -> Any: ... + +class chararray(ndarray[_ShapeType, _DType_co]): + def __getattr__(self, key: str) -> Any: ... + +class finfo: + def __getattr__(self, key: str) -> Any: ... + +class format_parser: + def __getattr__(self, key: str) -> Any: ... + +class iinfo: + def __getattr__(self, key: str) -> Any: ... + +class matrix(ndarray[_ShapeType, _DType_co]): + def __getattr__(self, key: str) -> Any: ... + +class memmap(ndarray[_ShapeType, _DType_co]): + def __getattr__(self, key: str) -> Any: ... + +class nditer: + def __getattr__(self, key: str) -> Any: ... + +class poly1d: + def __getattr__(self, key: str) -> Any: ... + +class recarray(ndarray[_ShapeType, _DType_co]): + def __getattr__(self, key: str) -> Any: ... + +class record(void): + def __getattr__(self, key: str) -> Any: ... + +class vectorize: + def __getattr__(self, key: str) -> Any: ... + +# Placeholders for miscellaneous objects ScalarType: Tuple[Type[Any], ...] -broadcast: Type[Any] -busdaycalendar: Type[Any] cast: Dict[generic, Callable[..., ndarray[Any, dtype[Any]]]] -chararray: Type[Any] -finfo: Type[Any] -format_parser: Type[Any] -iinfo: Type[Any] -matrix: Type[Any] -memmap: Type[Any] nbytes: Dict[generic, int] -nditer: Type[Any] -poly1d: Type[Any] -recarray: Type[Any] -record: Type[Any] typecodes: Dict[str, str] -vectorize: Type[Any] # Placeholders for Python-based functions def angle(z, deg=...): ... @@ -540,38 +572,64 @@ def vsplit(ary, indices_or_sections): ... def who(vardict=...): ... # Placeholders for C-based functions -arange: Callable[..., Any] -bincount: Callable[..., Any] -busday_count: Callable[..., Any] -busday_offset: Callable[..., Any] -can_cast: Callable[..., Any] -compare_chararrays: Callable[..., Any] -concatenate: Callable[..., Any] -copyto: Callable[..., Any] -datetime_as_string: Callable[..., Any] -datetime_data: Callable[..., Any] -dot: Callable[..., Any] -frombuffer: Callable[..., Any] -fromfile: Callable[..., Any] -fromiter: Callable[..., Any] -frompyfunc: Callable[..., Any] -fromstring: Callable[..., Any] -geterrobj: Callable[..., Any] -inner: Callable[..., Any] -is_busday: Callable[..., Any] -lexsort: Callable[..., Any] -may_share_memory: Callable[..., Any] -min_scalar_type: Callable[..., Any] -nested_iters: Callable[..., Any] -packbits: Callable[..., Any] -promote_types: Callable[..., Any] -putmask: Callable[..., Any] -result_type: Callable[..., Any] -seterrobj: Callable[..., Any] -shares_memory: Callable[..., Any] -unpackbits: Callable[..., Any] -vdot: Callable[..., Any] -where: Callable[..., Any] +# TODO: Sort out which parameters are positional-only +@overload +def arange(stop, dtype=..., *, like=...): ... +@overload +def arange(start, stop, step, dtype=..., *, like=...): ... +def bincount(x, weights=..., minlength=...): ... +def busday_count( + begindates, + enddates, + weekmask=..., + holidays=..., + busdaycal=..., + out=..., +): ... +def busday_offset( + dates, + offsets, + roll=..., + weekmask=..., + holidays=..., + busdaycal=..., + out=..., +): ... +def can_cast(from_, to, casting=...): ... +def compare_chararrays(a, b, cmp_op, rstrip): ... +def concatenate(__a, axis=..., out=..., dtype=..., casting=...): ... +def copyto(dst, src, casting=..., where=...): ... +def datetime_as_string(arr, unit=..., timezone=..., casting=...): ... +def datetime_data(__dtype): ... +def dot(a, b, out=...): ... +def frombuffer(buffer, dtype=..., count=..., offset=..., *, like=...): ... +def fromfile( + file, dtype=..., count=..., sep=..., offset=..., *, like=... +): ... +def fromiter(iter, dtype, count=..., *, like=...): ... +def frompyfunc(func, nin, nout, * identity): ... +def fromstring(string, dtype=..., count=..., sep=..., *, like=...): ... +def geterrobj(): ... +def inner(a, b): ... +def is_busday( + dates, weekmask=..., holidays=..., busdaycal=..., out=... +): ... +def lexsort(keys, axis=...): ... +def may_share_memory(a, b, max_work=...): ... +def min_scalar_type(a): ... +def nested_iters(*args, **kwargs): ... # TODO: Sort out parameters +def packbits(a, axis=..., bitorder=...): ... +def promote_types(type1, type2): ... +def putmask(a, mask, values): ... +def result_type(*arrays_and_dtypes): ... +def seterrobj(errobj): ... +def shares_memory(a, b, max_work=...): ... +def unpackbits(a, axis=..., count=..., bitorder=...): ... +def vdot(a, b): ... +@overload +def where(__condition): ... +@overload +def where(__condition, __x, __y): ... _NdArraySubClass = TypeVar("_NdArraySubClass", bound=ndarray) _DTypeScalar_co = TypeVar("_DTypeScalar_co", covariant=True, bound=generic) @@ -1375,7 +1433,7 @@ class ndarray(_ArrayOrScalarCommon, Generic[_ShapeType, _DType_co]): def imag(self, value: ArrayLike) -> None: ... def __new__( cls: Type[_ArraySelf], - shape: Sequence[int], + shape: _ShapeLike, dtype: DTypeLike = ..., buffer: _BufferType = ..., offset: int = ..., diff --git a/numpy/fft/__init__.py b/numpy/fft/__init__.py index a86bb3ac0..fd5e47580 100644 --- a/numpy/fft/__init__.py +++ b/numpy/fft/__init__.py @@ -200,9 +200,13 @@ For examples, see the various functions. """ +from . import _pocketfft, helper from ._pocketfft import * from .helper import * +__all__ = _pocketfft.__all__.copy() +__all__ += helper.__all__ + from numpy._pytesttester import PytestTester test = PytestTester(__name__) del PytestTester diff --git a/numpy/fft/__init__.pyi b/numpy/fft/__init__.pyi index 45190517f..bb4fae903 100644 --- a/numpy/fft/__init__.pyi +++ b/numpy/fft/__init__.pyi @@ -1,4 +1,6 @@ -from typing import Any +from typing import Any, List + +__all__: List[str] fft: Any ifft: Any diff --git a/numpy/linalg/__init__.py b/numpy/linalg/__init__.py index 3a53ac6ec..93943de38 100644 --- a/numpy/linalg/__init__.py +++ b/numpy/linalg/__init__.py @@ -70,8 +70,11 @@ Exceptions """ # To get sub-modules +from . import linalg from .linalg import * +__all__ = linalg.__all__.copy() + from numpy._pytesttester import PytestTester test = PytestTester(__name__) del PytestTester diff --git a/numpy/linalg/__init__.pyi b/numpy/linalg/__init__.pyi index ffb05bb81..39b061969 100644 --- a/numpy/linalg/__init__.pyi +++ b/numpy/linalg/__init__.pyi @@ -1,4 +1,6 @@ -from typing import Any +from typing import Any, List + +__all__: List[str] matrix_power: Any solve: Any diff --git a/numpy/polynomial/__init__.py b/numpy/polynomial/__init__.py index d629df29f..4b4361163 100644 --- a/numpy/polynomial/__init__.py +++ b/numpy/polynomial/__init__.py @@ -37,13 +37,13 @@ This eliminates the need to navigate to the corresponding submodules, e.g. The classes provide a more consistent and concise interface than the type-specific functions defined in the submodules for each type of polynomial. For example, to fit a Chebyshev polynomial with degree ``1`` to data given -by arrays ``xdata`` and ``ydata``, the +by arrays ``xdata`` and ``ydata``, the `~chebyshev.Chebyshev.fit` class method:: >>> from numpy.polynomial import Chebyshev >>> c = Chebyshev.fit(xdata, ydata, deg=1) -is preferred over the `chebyshev.chebfit` function from the +is preferred over the `chebyshev.chebfit` function from the ``np.polynomial.chebyshev`` module:: >>> from numpy.polynomial.chebyshev import chebfit @@ -76,7 +76,7 @@ Methods for creating polynomial instances. - ``Poly.basis(degree)`` -- Basis polynomial of given degree - ``Poly.identity()`` -- ``p`` where ``p(x) = x`` for all ``x`` -- ``Poly.fit(x, y, deg)`` -- ``p`` of degree ``deg`` with coefficients +- ``Poly.fit(x, y, deg)`` -- ``p`` of degree ``deg`` with coefficients determined by the least-squares fit to the data ``x``, ``y`` - ``Poly.fromroots(roots)`` -- ``p`` with specified roots - ``p.copy()`` -- Create a copy of ``p`` @@ -120,6 +120,16 @@ from .hermite import Hermite from .hermite_e import HermiteE from .laguerre import Laguerre +__all__ = [ + "set_default_printstyle", + "polynomial", "Polynomial", + "chebyshev", "Chebyshev", + "legendre", "Legendre", + "hermite", "Hermite", + "hermite_e", "HermiteE", + "laguerre", "Laguerre", +] + def set_default_printstyle(style): """ diff --git a/numpy/polynomial/__init__.pyi b/numpy/polynomial/__init__.pyi index 755f7521b..6a7406041 100644 --- a/numpy/polynomial/__init__.pyi +++ b/numpy/polynomial/__init__.pyi @@ -1,4 +1,4 @@ -from typing import Any +from typing import Any, List from numpy.polynomial import ( chebyshev as chebyshev, @@ -9,6 +9,8 @@ from numpy.polynomial import ( polynomial as polynomial, ) +__all__: List[str] + Polynomial: Any Chebyshev: Any Legendre: Any diff --git a/numpy/random/_generator.pyx b/numpy/random/_generator.pyx index 17a52a8d5..a68303501 100644 --- a/numpy/random/_generator.pyx +++ b/numpy/random/_generator.pyx @@ -4592,7 +4592,7 @@ def default_rng(seed=None): Examples -------- - ``default_rng`` is the reccomended constructor for the random number class + ``default_rng`` is the recommended constructor for the random number class ``Generator``. Here are several ways we can construct a random number generator using ``default_rng`` and the ``Generator`` class. diff --git a/numpy/typing/_shape.py b/numpy/typing/_shape.py index 4629046ea..b720c3ffc 100644 --- a/numpy/typing/_shape.py +++ b/numpy/typing/_shape.py @@ -1,6 +1,15 @@ +import sys from typing import Sequence, Tuple, Union +if sys.version_info >= (3, 8): + from typing import SupportsIndex +else: + try: + from typing_extensions import SupportsIndex + except ImportError: + SupportsIndex = NotImplemented + _Shape = Tuple[int, ...] # Anything that can be coerced to a shape tuple -_ShapeLike = Union[int, Sequence[int]] +_ShapeLike = Union[SupportsIndex, Sequence[SupportsIndex]] diff --git a/numpy/typing/tests/data/pass/array_constructors.py b/numpy/typing/tests/data/pass/array_constructors.py index 63208f139..206f70a15 100644 --- a/numpy/typing/tests/data/pass/array_constructors.py +++ b/numpy/typing/tests/data/pass/array_constructors.py @@ -1,11 +1,20 @@ +import sys from typing import List, Any import numpy as np + class Index: def __index__(self) -> int: return 0 -class SubClass(np.ndarray): ... + +class SubClass(np.ndarray): + pass + + +def func(i: int, j: int, **kwargs: Any) -> SubClass: + return B + i8 = np.int64(1) @@ -14,8 +23,9 @@ B = A.view(SubClass).copy() B_stack = np.array([[1], [1]]).view(SubClass) C = [1] -def func(i: int, j: int, **kwargs: Any) -> SubClass: - return B +if sys.version_info >= (3, 8): + np.ndarray(Index()) + np.ndarray([Index()]) np.array(1, dtype=float) np.array(1, copy=False) |
