diff options
| -rw-r--r-- | doc/TESTS.rst.txt | 2 | ||||
| -rw-r--r-- | doc/source/reference/random/index.rst | 3 | ||||
| -rw-r--r-- | doc/source/reference/random/new-or-different.rst | 12 | ||||
| -rw-r--r-- | numpy/compat/setup.py | 2 | ||||
| -rw-r--r-- | numpy/core/setup.py | 2 | ||||
| -rw-r--r-- | numpy/distutils/setup.py | 2 | ||||
| -rw-r--r-- | numpy/f2py/setup.py | 3 | ||||
| -rw-r--r-- | numpy/fft/setup.py | 2 | ||||
| -rw-r--r-- | numpy/lib/function_base.py | 22 | ||||
| -rw-r--r-- | numpy/lib/histograms.py | 10 | ||||
| -rw-r--r-- | numpy/lib/setup.py | 3 | ||||
| -rw-r--r-- | numpy/lib/tests/test_function_base.py | 69 | ||||
| -rw-r--r-- | numpy/linalg/setup.py | 2 | ||||
| -rw-r--r-- | numpy/ma/setup.py | 2 | ||||
| -rw-r--r-- | numpy/matrixlib/setup.py | 2 | ||||
| -rw-r--r-- | numpy/polynomial/setup.py | 2 | ||||
| -rw-r--r-- | numpy/random/setup.py | 3 | ||||
| -rw-r--r-- | numpy/setup.py | 2 | ||||
| -rwxr-xr-x | numpy/testing/setup.py | 2 | ||||
| -rwxr-xr-x | runtests.py | 22 | ||||
| -rw-r--r-- | tools/openblas_support.py | 34 | ||||
| -rw-r--r-- | tools/refguide_check.py | 2 |
22 files changed, 160 insertions, 45 deletions
diff --git a/doc/TESTS.rst.txt b/doc/TESTS.rst.txt index 007840b39..af47fe99c 100644 --- a/doc/TESTS.rst.txt +++ b/doc/TESTS.rst.txt @@ -256,7 +256,7 @@ section of your setup.py:: ... def configuration(parent_package='', top_path=None): ... - config.add_data_dir('tests') + config.add_subpackage('tests') return config ... diff --git a/doc/source/reference/random/index.rst b/doc/source/reference/random/index.rst index bda9c4d96..d559f2327 100644 --- a/doc/source/reference/random/index.rst +++ b/doc/source/reference/random/index.rst @@ -168,6 +168,9 @@ What's New or Different Python's `random.random`. * All BitGenerators in numpy use `SeedSequence` to convert seeds into initialized states. +* The addition of an ``axis`` keyword argument to methods such as + `Generator.choice`, `Generator.permutation`, and `Generator.shuffle` + improves support for sampling from and shuffling multi-dimensional arrays. See :ref:`new-or-different` for a complete list of improvements and differences from the traditional ``Randomstate``. diff --git a/doc/source/reference/random/new-or-different.rst b/doc/source/reference/random/new-or-different.rst index 1d6b09faf..03e7775a0 100644 --- a/doc/source/reference/random/new-or-different.rst +++ b/doc/source/reference/random/new-or-different.rst @@ -115,3 +115,15 @@ And in more detail: rg.random(out=existing[:2]) print(existing) +* Optional ``axis`` argument for methods like `~.Generator.choice`, + `~.Generator.permutation` and `~.Generator.shuffle` that controls which + axis an operation is performed over for multi-dimensional arrays. + +.. ipython:: python + + rg = Generator(PCG64(123456789)) + a = np.arange(12).reshape((3, 4)) + a + rg.choice(a, axis=1, size=5) + rg.shuffle(a, axis=1) # Shuffle in-place + a diff --git a/numpy/compat/setup.py b/numpy/compat/setup.py index afa511673..c1b34a2cc 100644 --- a/numpy/compat/setup.py +++ b/numpy/compat/setup.py @@ -2,7 +2,7 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('compat', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') return config if __name__ == '__main__': diff --git a/numpy/core/setup.py b/numpy/core/setup.py index 15e732614..76f3f5abe 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -961,7 +961,7 @@ def configuration(parent_package='',top_path=None): config.add_extension('_operand_flag_tests', sources=[join('src', 'umath', '_operand_flag_tests.c.src')]) - config.add_data_dir('tests') + config.add_subpackage('tests') config.add_data_dir('tests/data') config.make_svn_version_py() diff --git a/numpy/distutils/setup.py b/numpy/distutils/setup.py index 69d35f5c2..88cd1a160 100644 --- a/numpy/distutils/setup.py +++ b/numpy/distutils/setup.py @@ -4,7 +4,7 @@ def configuration(parent_package='',top_path=None): config = Configuration('distutils', parent_package, top_path) config.add_subpackage('command') config.add_subpackage('fcompiler') - config.add_data_dir('tests') + config.add_subpackage('tests') config.add_data_files('site.cfg') config.add_data_files('mingw/gfortran_vs2003_hack.c') config.make_config_py() diff --git a/numpy/f2py/setup.py b/numpy/f2py/setup.py index 6314c5af3..80b47e527 100644 --- a/numpy/f2py/setup.py +++ b/numpy/f2py/setup.py @@ -25,7 +25,8 @@ from __version__ import version def configuration(parent_package='', top_path=None): config = Configuration('f2py', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') + config.add_data_dir('tests/src') config.add_data_files( 'src/fortranobject.c', 'src/fortranobject.h') diff --git a/numpy/fft/setup.py b/numpy/fft/setup.py index e8204fcd3..9ed824e4f 100644 --- a/numpy/fft/setup.py +++ b/numpy/fft/setup.py @@ -4,7 +4,7 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('fft', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') # AIX needs to be told to use large file support - at all times defs = [('_LARGE_FILES', None)] if sys.platform[:3] == "aix" else [] diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 38acfd2d5..dea01d12d 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -2050,7 +2050,7 @@ class vectorize: self.pyfunc = pyfunc self.cache = cache self.signature = signature - self._ufunc = None # Caching to improve default performance + self._ufunc = {} # Caching to improve default performance if doc is None: self.__doc__ = pyfunc.__doc__ @@ -2115,14 +2115,22 @@ class vectorize: if self.otypes is not None: otypes = self.otypes - nout = len(otypes) - # Note logic here: We only *use* self._ufunc if func is self.pyfunc - # even though we set self._ufunc regardless. - if func is self.pyfunc and self._ufunc is not None: - ufunc = self._ufunc + # self._ufunc is a dictionary whose keys are the number of + # arguments (i.e. len(args)) and whose values are ufuncs created + # by frompyfunc. len(args) can be different for different calls if + # self.pyfunc has parameters with default values. We only use the + # cache when func is self.pyfunc, which occurs when the call uses + # only positional arguments and no arguments are excluded. + + nin = len(args) + nout = len(self.otypes) + if func is not self.pyfunc or nin not in self._ufunc: + ufunc = frompyfunc(func, nin, nout) else: - ufunc = self._ufunc = frompyfunc(func, len(args), nout) + ufunc = None # We'll get it from self._ufunc + if func is self.pyfunc: + ufunc = self._ufunc.setdefault(nin, ufunc) else: # Get number of outputs and output types by calling the function on # the first entries of args. We also cache the result to prevent diff --git a/numpy/lib/histograms.py b/numpy/lib/histograms.py index f080cc392..1a9b41ced 100644 --- a/numpy/lib/histograms.py +++ b/numpy/lib/histograms.py @@ -1047,7 +1047,15 @@ def histogramdd(sample, bins=10, range=None, normed=None, weights=None, raise ValueError( '`bins[{}]` must be positive, when an integer'.format(i)) smin, smax = _get_outer_edges(sample[:,i], range[i]) - edges[i] = np.linspace(smin, smax, bins[i] + 1) + try: + n = operator.index(bins[i]) + + except TypeError as e: + raise TypeError( + "`bins[{}]` must be an integer, when a scalar".format(i) + ) from e + + edges[i] = np.linspace(smin, smax, n + 1) elif np.ndim(bins[i]) == 1: edges[i] = np.asarray(bins[i]) if np.any(edges[i][:-1] > edges[i][1:]): diff --git a/numpy/lib/setup.py b/numpy/lib/setup.py index 5d0341d86..b3f441f38 100644 --- a/numpy/lib/setup.py +++ b/numpy/lib/setup.py @@ -2,7 +2,8 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('lib', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') + config.add_data_dir('tests/data') return config if __name__ == '__main__': diff --git a/numpy/lib/tests/test_function_base.py b/numpy/lib/tests/test_function_base.py index 23bf3296d..b4e928273 100644 --- a/numpy/lib/tests/test_function_base.py +++ b/numpy/lib/tests/test_function_base.py @@ -3,6 +3,7 @@ import warnings import sys import decimal from fractions import Fraction +import math import pytest import numpy as np @@ -1221,6 +1222,16 @@ class TestExtins: assert_array_equal(a, ac) +# _foo1 and _foo2 are used in some tests in TestVectorize. + +def _foo1(x, y=1.0): + return y*math.floor(x) + + +def _foo2(x, y=1.0, z=0.0): + return y*math.floor(x) + z + + class TestVectorize: def test_simple(self): @@ -1252,7 +1263,6 @@ class TestVectorize: assert_array_equal(y, x) def test_ufunc(self): - import math f = vectorize(math.cos) args = np.array([0, 0.5 * np.pi, np.pi, 1.5 * np.pi, 2 * np.pi]) r1 = f(args) @@ -1273,6 +1283,63 @@ class TestVectorize: r2 = np.array([3, 4, 5]) assert_array_equal(r1, r2) + def test_keywords_with_otypes_order1(self): + # gh-1620: The second call of f would crash with + # `ValueError: invalid number of arguments`. + f = vectorize(_foo1, otypes=[float]) + # We're testing the caching of ufuncs by vectorize, so the order + # of these function calls is an important part of the test. + r1 = f(np.arange(3.0), 1.0) + r2 = f(np.arange(3.0)) + assert_array_equal(r1, r2) + + def test_keywords_with_otypes_order2(self): + # gh-1620: The second call of f would crash with + # `ValueError: non-broadcastable output operand with shape () + # doesn't match the broadcast shape (3,)`. + f = vectorize(_foo1, otypes=[float]) + # We're testing the caching of ufuncs by vectorize, so the order + # of these function calls is an important part of the test. + r1 = f(np.arange(3.0)) + r2 = f(np.arange(3.0), 1.0) + assert_array_equal(r1, r2) + + def test_keywords_with_otypes_order3(self): + # gh-1620: The third call of f would crash with + # `ValueError: invalid number of arguments`. + f = vectorize(_foo1, otypes=[float]) + # We're testing the caching of ufuncs by vectorize, so the order + # of these function calls is an important part of the test. + r1 = f(np.arange(3.0)) + r2 = f(np.arange(3.0), y=1.0) + r3 = f(np.arange(3.0)) + assert_array_equal(r1, r2) + assert_array_equal(r1, r3) + + def test_keywords_with_otypes_several_kwd_args1(self): + # gh-1620 Make sure different uses of keyword arguments + # don't break the vectorized function. + f = vectorize(_foo2, otypes=[float]) + # We're testing the caching of ufuncs by vectorize, so the order + # of these function calls is an important part of the test. + r1 = f(10.4, z=100) + r2 = f(10.4, y=-1) + r3 = f(10.4) + assert_equal(r1, _foo2(10.4, z=100)) + assert_equal(r2, _foo2(10.4, y=-1)) + assert_equal(r3, _foo2(10.4)) + + def test_keywords_with_otypes_several_kwd_args2(self): + # gh-1620 Make sure different uses of keyword arguments + # don't break the vectorized function. + f = vectorize(_foo2, otypes=[float]) + # We're testing the caching of ufuncs by vectorize, so the order + # of these function calls is an important part of the test. + r1 = f(z=100, x=10.4, y=-1) + r2 = f(1, 2, 3) + assert_equal(r1, _foo2(z=100, x=10.4, y=-1)) + assert_equal(r2, _foo2(1, 2, 3)) + def test_keywords_no_func_code(self): # This needs to test a function that has keywords but # no func_code attribute, since otherwise vectorize will diff --git a/numpy/linalg/setup.py b/numpy/linalg/setup.py index acfab0a68..57fdd502b 100644 --- a/numpy/linalg/setup.py +++ b/numpy/linalg/setup.py @@ -6,7 +6,7 @@ def configuration(parent_package='', top_path=None): from numpy.distutils.system_info import get_info, system_info config = Configuration('linalg', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') # Configure lapack_lite diff --git a/numpy/ma/setup.py b/numpy/ma/setup.py index 144a961c2..d3f34c874 100644 --- a/numpy/ma/setup.py +++ b/numpy/ma/setup.py @@ -2,7 +2,7 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('ma', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') return config if __name__ == "__main__": diff --git a/numpy/matrixlib/setup.py b/numpy/matrixlib/setup.py index 529d2a2eb..19b3bb2de 100644 --- a/numpy/matrixlib/setup.py +++ b/numpy/matrixlib/setup.py @@ -2,7 +2,7 @@ def configuration(parent_package='', top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('matrixlib', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') return config if __name__ == "__main__": diff --git a/numpy/polynomial/setup.py b/numpy/polynomial/setup.py index 8fc82cba1..641464518 100644 --- a/numpy/polynomial/setup.py +++ b/numpy/polynomial/setup.py @@ -1,7 +1,7 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('polynomial', parent_package, top_path) - config.add_data_dir('tests') + config.add_subpackage('tests') return config if __name__ == '__main__': diff --git a/numpy/random/setup.py b/numpy/random/setup.py index 90ec42671..88ddb1268 100644 --- a/numpy/random/setup.py +++ b/numpy/random/setup.py @@ -31,7 +31,8 @@ def configuration(parent_package='', top_path=None): ('_LARGEFILE64_SOURCE', '1')] defs.append(('NPY_NO_DEPRECATED_API', 0)) - config.add_data_dir('tests') + config.add_subpackage('tests') + config.add_data_dir('tests/data') config.add_data_dir('_examples') EXTRA_LINK_ARGS = [] diff --git a/numpy/setup.py b/numpy/setup.py index fb9b36b78..52db6a68b 100644 --- a/numpy/setup.py +++ b/numpy/setup.py @@ -18,7 +18,7 @@ def configuration(parent_package='',top_path=None): config.add_subpackage('random') config.add_subpackage('testing') config.add_data_dir('doc') - config.add_data_dir('tests') + config.add_subpackage('tests') config.make_config_py() # installs __config__.py return config diff --git a/numpy/testing/setup.py b/numpy/testing/setup.py index f4970991c..13191f13f 100755 --- a/numpy/testing/setup.py +++ b/numpy/testing/setup.py @@ -5,7 +5,7 @@ def configuration(parent_package='',top_path=None): config = Configuration('testing', parent_package, top_path) config.add_subpackage('_private') - config.add_data_dir('tests') + config.add_subpackage('tests') return config if __name__ == '__main__': diff --git a/runtests.py b/runtests.py index e470f8a9d..7f1d55b85 100755 --- a/runtests.py +++ b/runtests.py @@ -125,7 +125,7 @@ def main(argv): "COMMIT. Note that you need to commit your " "changes first!")) parser.add_argument("args", metavar="ARGS", default=[], nargs=REMAINDER, - help="Arguments to pass to Nose, Python or shell") + help="Arguments to pass to Nose, asv, Python or shell") args = parser.parse_args(argv) if args.durations < 0: @@ -162,8 +162,10 @@ def main(argv): site_dir = os.path.sep.join(_temp.__file__.split(os.path.sep)[:-2]) extra_argv = args.args[:] - if extra_argv and extra_argv[0] == '--': - extra_argv = extra_argv[1:] + if not args.bench: + # extra_argv may also lists selected benchmarks + if extra_argv and extra_argv[0] == '--': + extra_argv = extra_argv[1:] if args.python: # Debugging issues with warnings is much easier if you can see them @@ -220,13 +222,21 @@ def main(argv): if args.bench: # Run ASV - items = extra_argv + for i, v in enumerate(extra_argv): + if v.startswith("--"): + items = extra_argv[:i] + if v == "--": + i += 1 # skip '--' indicating further are passed on. + bench_args = extra_argv[i:] + break + else: + items = extra_argv + bench_args = [] + if args.tests: items += args.tests if args.submodule: items += [args.submodule] - - bench_args = [] for a in items: bench_args.extend(['--bench', a]) diff --git a/tools/openblas_support.py b/tools/openblas_support.py index 105aae51f..a729662c5 100644 --- a/tools/openblas_support.py +++ b/tools/openblas_support.py @@ -14,7 +14,7 @@ OPENBLAS_V = '0.3.9' OPENBLAS_LONG = 'v0.3.7-527-g79fd006c' # the 0.3.7 is misleading BASE_LOC = 'https://anaconda.org/multibuild-wheels-staging/openblas-libs' BASEURL = f'{BASE_LOC}/{OPENBLAS_LONG}/download' -ARCHITECTURES = ['', 'windows', 'darwin', 'aarch64', 'x86', 'ppc64le', 's390x'] +ARCHITECTURES = ['', 'windows', 'darwin', 'aarch64', 'x86_64', 'i686', 'ppc64le', 's390x'] IS_32BIT = sys.maxsize < 2**32 def get_arch(): @@ -25,10 +25,10 @@ def get_arch(): else: ret = platform.uname().machine # What do 32 bit machines report? - # If they are a docker, they report x86_64 or i686 - if 'x86' in ret or ret == 'i686': - ret = 'x86' - assert ret in ARCHITECTURES + # If they are a docker, they can report x86_64 + if 'x86' in ret and IS_32BIT: + arch = 'i686' + assert ret in ARCHITECTURES, f'invalid architecture {ret}' return ret def get_ilp64(): @@ -38,15 +38,26 @@ def get_ilp64(): raise RuntimeError("NPY_USE_BLAS_ILP64 set on 32-bit arch") return "64_" +def get_manylinux(arch): + if arch in ('x86_64', 'i686'): + default = '2010' + else: + default = '2014' + ret = os.environ.get("MB_ML_VER", default) + # XXX For PEP 600 this can be a glibc version + assert ret in ('1', '2010', '2014'), f'invalid MB_ML_VER {ret}' + return ret + + def download_openblas(target, arch, ilp64): import urllib3 + ml_ver = get_manylinux(arch) fnsuffix = {None: "", "64_": "64_"}[ilp64] filename = '' - if arch in ('aarch64', 'ppc64le', 's390x'): - suffix = f'manylinux2014_{arch}.tar.gz' + if arch in ('aarch64', 'ppc64le', 's390x', 'x86_64', 'i686'): + suffix = f'manylinux{ml_ver}_{arch}.tar.gz' filename = f'{BASEURL}/openblas{fnsuffix}-{OPENBLAS_LONG}-{suffix}' typ = 'tar.gz' - typ = 'tar.gz' elif arch == 'darwin': suffix = 'macosx_10_9_x86_64-gf_1becaaa.tar.gz' filename = f'{BASEURL}/openblas{fnsuffix}-{OPENBLAS_LONG}-{suffix}' @@ -58,13 +69,6 @@ def download_openblas(target, arch, ilp64): suffix = 'win_amd64-gcc_7_1_0.zip' filename = f'{BASEURL}/openblas{fnsuffix}-{OPENBLAS_LONG}-{suffix}' typ = 'zip' - elif 'x86' in arch: - if IS_32BIT: - suffix = 'manylinux2010_i686.tar.gz' - else: - suffix = 'manylinux2010_x86_64.tar.gz' - filename = f'{BASEURL}/openblas{fnsuffix}-{OPENBLAS_LONG}-{suffix}' - typ = 'tar.gz' if not filename: return None print("Downloading:", filename, file=sys.stderr) diff --git a/tools/refguide_check.py b/tools/refguide_check.py index e6cfc8b77..31d2997d3 100644 --- a/tools/refguide_check.py +++ b/tools/refguide_check.py @@ -450,7 +450,7 @@ def validate_rst_syntax(text, name, dots=True): return False, "ERROR: %s: no documentation" % (name,) ok_unknown_items = set([ - 'mod', 'currentmodule', 'autosummary', 'data', 'attr', + 'mod', 'doc', 'currentmodule', 'autosummary', 'data', 'attr', 'obj', 'versionadded', 'versionchanged', 'module', 'class', 'ref', 'func', 'toctree', 'moduleauthor', 'term', 'c:member', 'sectionauthor', 'codeauthor', 'eq', 'doi', 'DOI', 'arXiv', 'arxiv' |
