diff options
77 files changed, 761 insertions, 251 deletions
diff --git a/.circleci/config.yml b/.circleci/config.yml index 70cb8adc0..86470e086 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -21,6 +21,8 @@ jobs: python3 -m venv venv . venv/bin/activate pip install cython sphinx matplotlib + sudo apt-get update + sudo apt-get install -y graphviz - run: name: build numpy @@ -93,7 +95,7 @@ jobs: if [ "${CIRCLE_BRANCH}" == "master" ]; then touch doc/neps/_build/html/.nojekyll - ./tools/push_to_repo.py doc/neps/_build/html \ + ./tools/ci/push_docs_to_repo.py doc/neps/_build/html \ git@github.com:numpy/neps.git \ --committer "numpy-circleci-bot" \ --email "numpy-circleci-bot@nomail" \ diff --git a/doc/Makefile b/doc/Makefile index d414d26d7..667dbef29 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,7 +1,7 @@ # Makefile for Sphinx documentation # -PYVER = 2.7 +PYVER = 3.6 PYTHON = python$(PYVER) # You can set these variables from the command line. diff --git a/doc/neps/.gitignore b/doc/neps/.gitignore new file mode 100644 index 000000000..04163f707 --- /dev/null +++ b/doc/neps/.gitignore @@ -0,0 +1 @@ +index.rst diff --git a/doc/neps/Makefile b/doc/neps/Makefile index 2d1a063de..3c023ae9b 100644 --- a/doc/neps/Makefile +++ b/doc/neps/Makefile @@ -2,7 +2,7 @@ # # You can set these variables from the command line. -SPHINXOPTS = +SPHINXOPTS = -W SPHINXBUILD = sphinx-build SPHINXPROJ = NumPyEnhancementProposals SOURCEDIR = . @@ -12,9 +12,12 @@ BUILDDIR = _build help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) -.PHONY: help Makefile +.PHONY: help Makefile index + +index: + python tools/build_index.py # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). -%: Makefile +%: Makefile index @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/neps/index.rst b/doc/neps/index.rst.tmpl index 8a2df4078..8d0c5da77 100644 --- a/doc/neps/index.rst +++ b/doc/neps/index.rst.tmpl @@ -14,9 +14,11 @@ Meta-NEPs (NEPs about NEPs or Processes) .. toctree:: :maxdepth: 1 - nep-0000 - nep-template +{% for nep, tags in neps.items() if tags['Type'] == 'Process' %} + NEP {{ nep }} — {{ tags['Title'] }} <{{ tags['Filename'] }}> +{% endfor %} + nep-template Accepted NEPs, implementation in progress ----------------------------------------- @@ -24,8 +26,9 @@ Accepted NEPs, implementation in progress .. toctree:: :maxdepth: 1 - nep-0014-dropping-python2.7-proposal - +{% for nep, tags in neps.items() if tags['Status'] == 'Accepted' %} + NEP {{ nep }} — {{ tags['Title'] }} <{{ tags['Filename'] }}> +{% endfor %} Implemented NEPs ---------------- @@ -33,12 +36,9 @@ Implemented NEPs .. toctree:: :maxdepth: 1 - nep-0001-npy-format - nep-0005-generalized-ufuncs - nep-0007-datetime-proposal - nep-0010-new-iterator-ufunc - nep-0013-ufunc-overrides - +{% for nep, tags in neps.items() if tags['Status'] == 'Final' %} + NEP {{ nep }} — {{ tags['Title'] }} <{{ tags['Filename'] }}> +{% endfor %} Defunct NEPs ------------ @@ -46,11 +46,6 @@ Defunct NEPs .. toctree:: :maxdepth: 1 - nep-0002-warnfix - nep-0003-math_config_clean - nep-0004-datetime-proposal3 - nep-0006-newbugtracker - nep-0008-groupby_additions - nep-0009-structured_array_extensions - nep-0011-deferred-ufunc-evaluation - nep-0012-missing-data +{% for nep, tags in neps.items() if tags['Status'] == 'Deferred' %} + NEP {{ nep }} — {{ tags['Title'] }} <{{ tags['Filename'] }}> +{% endfor %} diff --git a/doc/neps/nep-0000.rst b/doc/neps/nep-0000.rst index ae8603c62..a7d6d7115 100644 --- a/doc/neps/nep-0000.rst +++ b/doc/neps/nep-0000.rst @@ -1,6 +1,6 @@ -======================= -NEP Purpose and Process -======================= +=================== +Purpose and Process +=================== :Author: Jarrod Millman <millman@berkeley.edu> :Status: Draft @@ -121,9 +121,12 @@ updated accordingly. In addition to updating the status field, at the very least the ``Resolution`` header should be added with a link to the relevant post in the mailing list archives. -NEPs can also be ``Replaced`` by a different NEP, rendering the original -obsolete. Process NEPs may also have a status of -``Active`` if they are never meant to be completed. E.g. NEP 0 (this NEP). +NEPs can also be ``Superseded`` by a different NEP, rendering the +original obsolete. The ``Replaced-By`` and ``Replaces`` headers +should be added to the original and new NEPs respectively. + +Process NEPs may also have a status of ``Active`` if they are never +meant to be completed, e.g. NEP 0 (this NEP). Maintenance diff --git a/doc/neps/nep-0001-npy-format.rst b/doc/neps/nep-0001-npy-format.rst index 3f12e1bf1..2057aed83 100644 --- a/doc/neps/nep-0001-npy-format.rst +++ b/doc/neps/nep-0001-npy-format.rst @@ -2,10 +2,9 @@ A Simple File Format for NumPy Arrays ===================================== -Author: Robert Kern <robert.kern@gmail.com> -Status: Draft -Created: 20-Dec-2007 - +:Author: Robert Kern <robert.kern@gmail.com> +:Status: Final +:Created: 20-Dec-2007 Abstract -------- diff --git a/doc/neps/nep-0002-warnfix.rst b/doc/neps/nep-0002-warnfix.rst index 4b0a2a56e..60dc885b2 100644 --- a/doc/neps/nep-0002-warnfix.rst +++ b/doc/neps/nep-0002-warnfix.rst @@ -5,6 +5,7 @@ A proposal to build numpy without warning with a big set of warning flags :Author: David Cournapeau :Contact: david@ar.media.kyoto-u.ac.jp :Date: 2008-09-04 +:Status: Deferred Executive summary ================= @@ -20,13 +21,13 @@ Warning flags ============= Each compiler detects a different set of potential errors. The baseline will -be gcc -Wall -W -Wextra. Ideally, a complete set would be nice: +be gcc -Wall -W -Wextra. Ideally, a complete set would be nice:: --W -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return --Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast --Wwrite-strings " + -W -Wall -Wextra -Wstrict-prototypes -Wmissing-prototypes -Waggregate-return + -Wcast-align -Wcast-qual -Wnested-externs -Wshadow -Wbad-function-cast + -Wwrite-strings " -Intel compiler, VS with /W3 /Wall, Sun compilers have extra warnings too. +Intel compiler, VS with ``/W3 /Wall``, Sun compilers have extra warnings too. Kind of warnings ================ @@ -46,27 +47,29 @@ solve it is to tag the function argument with a macro NPY_UNUSED. This macro uses compiler specific code to tag the variable, and mangle it such as it is not possible to use it accidentally once it is tagged. -The code to apply compiler specific option could be: +The code to apply compiler specific option could be:: -#if defined(__GNUC__) - #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) -# elif defined(__ICC) - #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) -#else - #define __COMP_NPY_UNUSED -#endif + #if defined(__GNUC__) + #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) + # elif defined(__ICC) + #define __COMP_NPY_UNUSED __attribute__ ((__unused__)) + #else + #define __COMP_NPY_UNUSED + #endif -The variable mangling would be: +The variable mangling would be:: -#define NPY_UNUSED(x) (__NPY_UNUSED_TAGGED ## x) __COMP_NPY_UNUSED + #define NPY_UNUSED(x) (__NPY_UNUSED_TAGGED ## x) __COMP_NPY_UNUSED -When applied to a variable, one would get: +When applied to a variable, one would get:: -int foo(int * NPY_UNUSED(dummy)) + int foo(int * NPY_UNUSED(dummy)) expanded to -int foo(int * __NPY_UNUSED_TAGGEDdummy __COMP_NPY_UNUSED) +:: + + int foo(int * __NPY_UNUSED_TAGGEDdummy __COMP_NPY_UNUSED) Thus avoiding any accidental use of the variable. The mangling is pure C, and thuse portable. The per-variable warning disabling is compiler specific. diff --git a/doc/neps/nep-0003-math_config_clean.rst b/doc/neps/nep-0003-math_config_clean.rst index 27c0adfa1..5af907437 100644 --- a/doc/neps/nep-0003-math_config_clean.rst +++ b/doc/neps/nep-0003-math_config_clean.rst @@ -5,6 +5,7 @@ Cleaning the math configuration of numpy.core :Author: David Cournapeau :Contact: david@ar.media.kyoto-u.ac.jp :Date: 2008-09-04 +:Status: Deferred Executive summary ================= diff --git a/doc/neps/nep-0004-datetime-proposal3.rst b/doc/neps/nep-0004-datetime-proposal3.rst index fcfb39e54..46d8e314b 100644 --- a/doc/neps/nep-0004-datetime-proposal3.rst +++ b/doc/neps/nep-0004-datetime-proposal3.rst @@ -7,7 +7,7 @@ :Author: Ivan Vilata i Balaguer :Contact: ivan@selidor.net :Date: 2008-07-30 - +:Status: Deferred Executive summary ================= diff --git a/doc/neps/nep-0005-generalized-ufuncs.rst b/doc/neps/nep-0005-generalized-ufuncs.rst index 98e436990..54b2b370e 100644 --- a/doc/neps/nep-0005-generalized-ufuncs.rst +++ b/doc/neps/nep-0005-generalized-ufuncs.rst @@ -2,6 +2,8 @@ Generalized Universal Functions =============================== +:Status: Final + There is a general need for looping over not only functions on scalars but also over functions on vectors (or arrays), as explained on http://scipy.org/scipy/numpy/wiki/GeneralLoopingFunctions. We propose diff --git a/doc/neps/nep-0006-newbugtracker.rst b/doc/neps/nep-0006-newbugtracker.rst index 5af633552..2b9344ed0 100644 --- a/doc/neps/nep-0006-newbugtracker.rst +++ b/doc/neps/nep-0006-newbugtracker.rst @@ -3,6 +3,7 @@ Replacing Trac with a different bug tracker =========================================== :Author: David Cournapeau, Stefan van der Walt +:Status: Deferred Some release managers of both numpy and scipy are becoming more and more dissatisfied with the current development workflow, in particular for bug diff --git a/doc/neps/nep-0007-datetime-proposal.rst b/doc/neps/nep-0007-datetime-proposal.rst index 76c361f4f..72d48d244 100644 --- a/doc/neps/nep-0007-datetime-proposal.rst +++ b/doc/neps/nep-0007-datetime-proposal.rst @@ -5,6 +5,7 @@ :Author: Travis Oliphant :Contact: oliphant@enthought.com :Date: 2009-06-09 +:Status: Final Revised only slightly from the third proposal by @@ -14,7 +15,6 @@ Revised only slightly from the third proposal by :Contact: ivan@selidor.net :Date: 2008-07-30 - Executive summary ================= diff --git a/doc/neps/nep-0008-groupby_additions.rst b/doc/neps/nep-0008-groupby_additions.rst index a86bdd642..fa02f2f9c 100644 --- a/doc/neps/nep-0008-groupby_additions.rst +++ b/doc/neps/nep-0008-groupby_additions.rst @@ -5,6 +5,7 @@ :Author: Travis Oliphant :Contact: oliphant@enthought.com :Date: 2010-04-27 +:Status: Deferred Executive summary @@ -22,9 +23,9 @@ Example Use Case ================ Suppose you have a NumPy structured array containing information about the number of purchases at several stores over multiple days. To be clear, the -structured array data-type is: +structured array data-type is:: -dt = [('year', i2), ('month', i1), ('day', i1), ('time', float), + dt = [('year', i2), ('month', i1), ('day', i1), ('time', float), ('store', i4), ('SKU', 'S6'), ('number', i4)] Suppose there is a 1-d NumPy array of this data-type and you would like @@ -98,14 +99,5 @@ reduceby:: Functions proposed ================== -segment:: - - -edges:: - - -.. Local Variables: -.. mode: rst -.. coding: utf-8 -.. fill-column: 72 -.. End: +- segment +- edges diff --git a/doc/neps/nep-0009-structured_array_extensions.rst b/doc/neps/nep-0009-structured_array_extensions.rst index a4248362c..695d0d516 100644 --- a/doc/neps/nep-0009-structured_array_extensions.rst +++ b/doc/neps/nep-0009-structured_array_extensions.rst @@ -2,6 +2,8 @@ Structured array extensions =========================== +:Status: Deferred + 1. Create with-style context that makes "named-columns" available as names in the namespace. with np.columns(array): diff --git a/doc/neps/nep-0010-new-iterator-ufunc.rst b/doc/neps/nep-0010-new-iterator-ufunc.rst index 7a9e7627c..7b388a974 100644 --- a/doc/neps/nep-0010-new-iterator-ufunc.rst +++ b/doc/neps/nep-0010-new-iterator-ufunc.rst @@ -5,6 +5,7 @@ Optimizing Iterator/UFunc Performance :Author: Mark Wiebe <mwwiebe@gmail.com> :Content-Type: text/x-rst :Created: 25-Nov-2010 +:Status: Final ***************** Table of Contents diff --git a/doc/neps/nep-0011-deferred-ufunc-evaluation.rst b/doc/neps/nep-0011-deferred-ufunc-evaluation.rst index b00c0dd2d..5f5de3518 100644 --- a/doc/neps/nep-0011-deferred-ufunc-evaluation.rst +++ b/doc/neps/nep-0011-deferred-ufunc-evaluation.rst @@ -5,6 +5,7 @@ Deferred UFunc Evaluation :Author: Mark Wiebe <mwwiebe@gmail.com> :Content-Type: text/x-rst :Created: 30-Nov-2010 +:Status: Deferred ******** Abstract diff --git a/doc/neps/nep-0012-missing-data.rst b/doc/neps/nep-0012-missing-data.rst index 00a6034f4..1553339f4 100644 --- a/doc/neps/nep-0012-missing-data.rst +++ b/doc/neps/nep-0012-missing-data.rst @@ -6,6 +6,7 @@ Missing Data Functionality in NumPy :Copyright: Copyright 2011 by Enthought, Inc :License: CC By-SA 3.0 (http://creativecommons.org/licenses/by-sa/3.0/) :Date: 2011-06-23 +:Status: Deferred ***************** Table of Contents diff --git a/doc/neps/nep-0013-ufunc-overrides.rst b/doc/neps/nep-0013-ufunc-overrides.rst index 90869e1ac..c97b69023 100644 --- a/doc/neps/nep-0013-ufunc-overrides.rst +++ b/doc/neps/nep-0013-ufunc-overrides.rst @@ -1,5 +1,3 @@ -.. _neps.ufunc-overrides: - ================================= A Mechanism for Overriding Ufuncs ================================= @@ -19,6 +17,8 @@ A Mechanism for Overriding Ufuncs :Author: Stephan Hoyer :Date: 2017-03-31 +:Status: Final + Executive summary ================= @@ -154,8 +154,8 @@ Here: - *ufunc* is the ufunc object that was called. - *method* is a string indicating how the Ufunc was called, either ``"__call__"`` to indicate it was called directly, or one of its - :ref:`methods<ufuncs.methods>`: ``"reduce"``, ``"accumulate"``, - ``"reduceat"``, ``"outer"``, or ``"at"``. + methods: ``"reduce"``, ``"accumulate"``, ``"reduceat"``, ``"outer"``, + or ``"at"``. - *inputs* is a tuple of the input arguments to the ``ufunc`` - *kwargs* contains any optional or keyword arguments passed to the function. This includes any ``out`` arguments, which are always diff --git a/doc/neps/nep-0014-dropping-python2.7-proposal.rst b/doc/neps/nep-0014-dropping-python2.7-proposal.rst index 3cfe50bd0..6cfd4707f 100644 --- a/doc/neps/nep-0014-dropping-python2.7-proposal.rst +++ b/doc/neps/nep-0014-dropping-python2.7-proposal.rst @@ -2,6 +2,9 @@ Plan for dropping Python 2.7 support ==================================== +:Status: Accepted +:Resolution: https://mail.python.org/pipermail/numpy-discussion/2017-November/077419.html + The Python core team plans to stop supporting Python 2 in 2020. The NumPy project has supported both Python 2 and Python 3 in parallel since 2010, and has found that supporting Python 2 is an increasing burden on our limited diff --git a/doc/neps/nep-template.rst b/doc/neps/nep-template.rst index d51ad3688..56b06049e 100644 --- a/doc/neps/nep-template.rst +++ b/doc/neps/nep-template.rst @@ -4,7 +4,7 @@ NEP Template and Instructions :Author: <list of authors' real names and optionally, email addresses> :Status: <Draft | Active | Accepted | Deferred | Rejected | Withdrawn | Final | Superseded> -:Type: <Standards Track | Informational | Process> +:Type: <Standards Track | Process> :Created: <date created on, in yyyy-mm-dd format> diff --git a/doc/neps/tools/build_index.py b/doc/neps/tools/build_index.py new file mode 100644 index 000000000..65225c995 --- /dev/null +++ b/doc/neps/tools/build_index.py @@ -0,0 +1,99 @@ +""" +Scan the directory of nep files and extract their metadata. The +metadata is passed to Jinja for filling out `index.rst.tmpl`. +""" + +import os +import sys +import jinja2 +import glob +import re + + +def render(tpl_path, context): + path, filename = os.path.split(tpl_path) + return jinja2.Environment( + loader=jinja2.FileSystemLoader(path or './') + ).get_template(filename).render(context) + +def nep_metadata(): + ignore = ('nep-template.rst') + sources = sorted(glob.glob(r'nep-*.rst')) + sources = [s for s in sources if not s in ignore] + + meta_re = r':([a-zA-Z\-]*): (.*)' + + neps = {} + print('Loading metadata for:') + for source in sources: + print(f' - {source}') + nr = int(re.match(r'nep-([0-9]{4}).*\.rst', source).group(1)) + + with open(source) as f: + lines = f.readlines() + tags = [re.match(meta_re, line) for line in lines] + tags = [match.groups() for match in tags if match is not None] + tags = {tag[0]: tag[1] for tag in tags} + + # We could do a clever regexp, but for now just assume the title is + # the second line of the document + tags['Title'] = lines[1].strip() + tags['Filename'] = source + + + if tags['Status'] in ('Accepted', 'Rejected', 'Withdrawn'): + if not 'Resolution' in tags: + raise RuntimeError( + f'NEP {nr} is Accepted/Rejected/Withdrawn but ' + 'has no Resolution tag' + ) + + neps[nr] = tags + + # Now that we have all of the NEP metadata, do some global consistency + # checks + + for nr, tags in neps.items(): + if tags['Status'] == 'Superseded': + if not 'Replaced-By' in tags: + raise RuntimeError( + f'NEP {nr} has been Superseded, but has no Replaced-By tag' + ) + + replaced_by = int(tags['Replaced-By']) + replacement_nep = neps[replaced_by] + + if not 'Replaces' in replacement_nep: + raise RuntimeError( + f'NEP {nr} is superseded by {replaced_by}, but that NEP has ' + f"no Replaces tag." + ) + + if not int(replacement_nep['Replaces']) == nr: + raise RuntimeError( + f'NEP {nr} is superseded by {replaced_by}, but that NEP has a ' + f"Replaces tag of `{replacement_nep['Replaces']}`." + ) + + if 'Replaces' in tags: + replaced_nep = int(tags['Replaces']) + replaced_nep_tags = neps[replaced_nep] + if not replaced_nep_tags['Status'] == 'Superseded': + raise RuntimeError( + f'NEP {nr} replaces {replaced_nep}, but that NEP has not ' + f'been set to Superseded' + ) + + return {'neps': neps} + + +infile = 'index.rst.tmpl' +outfile = 'index.rst' + +meta = nep_metadata() + +print(f'Compiling {infile} -> {outfile}') +index = render(infile, meta) + +with open(outfile, 'w') as f: + f.write(index) diff --git a/doc/release/1.15.0-notes.rst b/doc/release/1.15.0-notes.rst index c7bf0b7bc..cff75c477 100644 --- a/doc/release/1.15.0-notes.rst +++ b/doc/release/1.15.0-notes.rst @@ -19,7 +19,7 @@ New functions for the scope of the ``with`` block:: >>> with np.printoptions(precision=2): - ... print(np.array([2.0])) / 3 + ... print(np.array([2.0]) / 3) [0.67] * `np.histogram_bin_edges`, a function to get the edges of the bins used by a histogram @@ -92,6 +92,10 @@ Creating a full iOS-compatible NumPy package requires building for the 5 architectures supported by iOS (i386, x86_64, armv7, armv7s and arm64), and combining these 5 compiled builds products into a single "fat" binary. +Build system +------------ +Added experimental support for the 64-bit RISC-V architecture. + Improvements ============ @@ -175,5 +179,19 @@ This change makes it easier to write Python 2/3 compatible code using ``from __future__ import unicode_literals``, which previously would cause string literal field names to raise a TypeError in Python 2. +``sort`` functions accept ``kind='stable'`` +------------------------------------------- +Up until now, to perform a stable sort on the data, the user must do:: + + >>> np.sort([5, 2, 6, 2, 1], kind='mergesort') + [1, 2, 2, 5, 6] + +because merge sort is the only stable sorting algorithm available in +NumPy. However, having kind='mergesort' does not make it explicit that +the user wants to perform a stable sort thus harming the readability. + +This change allows the user to specify kind='stable' thus clarifying +the intent. + Changes ======= diff --git a/doc/source/user/building.rst b/doc/source/user/building.rst index b98f89c2d..76eb48487 100644 --- a/doc/source/user/building.rst +++ b/doc/source/user/building.rst @@ -132,6 +132,8 @@ Supplying additional compiler flags Additional compiler flags can be supplied by setting the ``OPT``, ``FOPT`` (for Fortran), and ``CC`` environment variables. +When providing options that should improve the performance of the code ensure +that you also set ``-DNDEBUG`` so that debugging code is not executed. Building with ATLAS support diff --git a/doc/summarize.py b/doc/summarize.py index 972e298f4..cfce2713e 100755 --- a/doc/summarize.py +++ b/doc/summarize.py @@ -9,7 +9,7 @@ from __future__ import division, absolute_import, print_function import os, glob, re, sys, inspect, optparse try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/__init__.py b/numpy/__init__.py index db99294bc..db7bc0368 100644 --- a/numpy/__init__.py +++ b/numpy/__init__.py @@ -150,7 +150,6 @@ else: # no-one else in the world is using it (though I hope not) from .testing import Tester, _numpy_tester test = _numpy_tester().test - bench = _numpy_tester().bench # Allow distributors to run custom init code from . import _distributor_init diff --git a/numpy/add_newdocs.py b/numpy/add_newdocs.py index 316b38e77..0a7b2b13d 100644 --- a/numpy/add_newdocs.py +++ b/numpy/add_newdocs.py @@ -4494,7 +4494,7 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('sort', axis : int, optional Axis along which to sort. Default is -1, which means sort along the last axis. - kind : {'quicksort', 'mergesort', 'heapsort'}, optional + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional Sorting algorithm. Default is 'quicksort'. order : str or list of str, optional When `a` is an array with fields defined, this argument specifies diff --git a/numpy/core/__init__.py b/numpy/core/__init__.py index 6db484de4..264324503 100644 --- a/numpy/core/__init__.py +++ b/numpy/core/__init__.py @@ -73,7 +73,6 @@ __all__ += einsumfunc.__all__ from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench # Make it possible so that ufuncs can be pickled # Here are the loading and unloading functions diff --git a/numpy/core/code_generators/generate_umath.py b/numpy/core/code_generators/generate_umath.py index ebcf864ea..1d3550e06 100644 --- a/numpy/core/code_generators/generate_umath.py +++ b/numpy/core/code_generators/generate_umath.py @@ -966,7 +966,7 @@ def make_arrays(funcdict): for vt in t.simd: code2list.append(textwrap.dedent("""\ #ifdef HAVE_ATTRIBUTE_TARGET_{ISA} - if (NPY_CPU_SUPPORTS_{ISA}) {{ + if (npy_cpu_supports("{ISA}")) {{ {fname}_functions[{idx}] = {type}_{fname}_{isa}; }} #endif @@ -1073,7 +1073,7 @@ def make_code(funcdict, filename): Please make changes to the code generator program (%s) **/ - + #include "cpuid.h" %s static int diff --git a/numpy/core/code_generators/ufunc_docstrings.py b/numpy/core/code_generators/ufunc_docstrings.py index 75dee7084..c7e5cf600 100644 --- a/numpy/core/code_generators/ufunc_docstrings.py +++ b/numpy/core/code_generators/ufunc_docstrings.py @@ -18,23 +18,36 @@ def get(name): return docdict.get(name) # common parameter text to all ufuncs -_params_text = textwrap.dedent(""" - out : ndarray, None, or tuple of ndarray and None, optional - A location into which the result is stored. If provided, it must have - a shape that the inputs broadcast to. If not provided or `None`, - a freshly-allocated array is returned. A tuple (possible only as a - keyword argument) must have length equal to the number of outputs. - where : array_like, optional - Values of True indicate to calculate the ufunc at that position, values - of False indicate to leave the value in the output alone. - **kwargs - For other keyword-only arguments, see the - :ref:`ufunc docs <ufuncs.kwargs>`. -""").strip() +subst = { + 'PARAMS': textwrap.dedent(""" + out : ndarray, None, or tuple of ndarray and None, optional + A location into which the result is stored. If provided, it must have + a shape that the inputs broadcast to. If not provided or `None`, + a freshly-allocated array is returned. A tuple (possible only as a + keyword argument) must have length equal to the number of outputs. + where : array_like, optional + Values of True indicate to calculate the ufunc at that position, values + of False indicate to leave the value in the output alone. + **kwargs + For other keyword-only arguments, see the + :ref:`ufunc docs <ufuncs.kwargs>`. + """).strip(), + 'OUT_SCALAR_1': "This is a scalar if `x` is a scalar.", + 'OUT_SCALAR_2': "This is a scalar if both `x1` and `x2` are scalars.", +} def add_newdoc(place, name, doc): doc = textwrap.dedent(doc).strip() - doc = doc.replace('$PARAMS', _params_text) + + if name[0] != '_': + if '\nx :' in doc: + assert '$OUT_SCALAR_1' in doc, "in {}".format(name) + elif '\nx2 :' in doc or '\nx1, x2 :' in doc: + assert '$OUT_SCALAR_2' in doc, "in {}".format(name) + else: + assert False, "Could not detect number of inputs in {}".format(name) + for k, v in subst.items(): + doc = doc.replace('$' + k, v) docdict['.'.join((place, name))] = doc @@ -57,6 +70,7 @@ add_newdoc('numpy.core.umath', 'absolute', An ndarray containing the absolute value of each element in `x`. For complex input, ``a + ib``, the absolute value is :math:`\\sqrt{ a^2 + b^2 }`. + $OUT_SCALAR_1 Examples -------- @@ -97,8 +111,8 @@ add_newdoc('numpy.core.umath', 'add', Returns ------- add : ndarray or scalar - The sum of `x1` and `x2`, element-wise. Returns a scalar if - both `x1` and `x2` are scalars. + The sum of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 Notes ----- @@ -134,9 +148,8 @@ add_newdoc('numpy.core.umath', 'arccos', ------- angle : ndarray The angle of the ray intersecting the unit circle at the given - `x`-coordinate in radians [0, pi]. If `x` is a scalar then a - scalar is returned, otherwise an array of the same shape as `x` - is returned. + `x`-coordinate in radians [0, pi]. + $OUT_SCALAR_1 See Also -------- @@ -194,6 +207,7 @@ add_newdoc('numpy.core.umath', 'arccosh', ------- arccosh : ndarray Array of the same shape as `x`. + $OUT_SCALAR_1 See Also -------- @@ -244,8 +258,8 @@ add_newdoc('numpy.core.umath', 'arcsin', ------- angle : ndarray The inverse sine of each element in `x`, in radians and in the - closed interval ``[-pi/2, pi/2]``. If `x` is a scalar, a scalar - is returned, otherwise an array. + closed interval ``[-pi/2, pi/2]``. + $OUT_SCALAR_1 See Also -------- @@ -296,8 +310,9 @@ add_newdoc('numpy.core.umath', 'arcsinh', Returns ------- - out : ndarray + out : ndarray or scalar Array of the same shape as `x`. + $OUT_SCALAR_1 Notes ----- @@ -342,10 +357,10 @@ add_newdoc('numpy.core.umath', 'arctan', Returns ------- - out : ndarray + out : ndarray or scalar Out has the same shape as `x`. Its real part is in ``[-pi/2, pi/2]`` (``arctan(+/-inf)`` returns ``+/-pi/2``). - It is a scalar if `x` is a scalar. + $OUT_SCALAR_1 See Also -------- @@ -424,6 +439,7 @@ add_newdoc('numpy.core.umath', 'arctan2', ------- angle : ndarray Array of angles in radians, in the range ``[-pi, pi]``. + $OUT_SCALAR_2 See Also -------- @@ -490,8 +506,9 @@ add_newdoc('numpy.core.umath', 'arctanh', Returns ------- - out : ndarray + out : ndarray or scalar Array of the same shape as `x`. + $OUT_SCALAR_1 See Also -------- @@ -543,8 +560,9 @@ add_newdoc('numpy.core.umath', 'bitwise_and', Returns ------- - out : array_like + out : ndarray or scalar Result. + $OUT_SCALAR_2 See Also -------- @@ -595,8 +613,9 @@ add_newdoc('numpy.core.umath', 'bitwise_or', Returns ------- - out : array_like + out : ndarray or scalar Result. + $OUT_SCALAR_2 See Also -------- @@ -652,8 +671,9 @@ add_newdoc('numpy.core.umath', 'bitwise_xor', Returns ------- - out : array_like + out : ndarray or scalar Result. + $OUT_SCALAR_2 See Also -------- @@ -703,6 +723,7 @@ add_newdoc('numpy.core.umath', 'ceil', ------- y : ndarray or scalar The ceiling of each element in `x`, with `float` dtype. + $OUT_SCALAR_1 See Also -------- @@ -734,6 +755,7 @@ add_newdoc('numpy.core.umath', 'trunc', ------- y : ndarray or scalar The truncated value of each element in `x`. + $OUT_SCALAR_1 See Also -------- @@ -768,6 +790,7 @@ add_newdoc('numpy.core.umath', 'conjugate', ------- y : ndarray The complex conjugate of `x`, with same dtype as `y`. + $OUT_SCALAR_1 Examples -------- @@ -795,6 +818,7 @@ add_newdoc('numpy.core.umath', 'cos', ------- y : ndarray The corresponding cosine values. + $OUT_SCALAR_1 Notes ----- @@ -838,8 +862,9 @@ add_newdoc('numpy.core.umath', 'cosh', Returns ------- - out : ndarray + out : ndarray or scalar Output array of same shape as `x`. + $OUT_SCALAR_1 Examples -------- @@ -870,6 +895,7 @@ add_newdoc('numpy.core.umath', 'degrees', y : ndarray of floats The corresponding degree values; if `out` was supplied this is a reference to it. + $OUT_SCALAR_1 See Also -------- @@ -905,6 +931,7 @@ add_newdoc('numpy.core.umath', 'rad2deg', ------- y : ndarray The corresponding angle in degrees. + $OUT_SCALAR_1 See Also -------- @@ -946,8 +973,9 @@ add_newdoc('numpy.core.umath', 'heaviside', Returns ------- - out : ndarray + out : ndarray or scalar The output array, element-wise Heaviside step function of `x1`. + $OUT_SCALAR_2 Notes ----- @@ -981,8 +1009,8 @@ add_newdoc('numpy.core.umath', 'divide', Returns ------- y : ndarray or scalar - The quotient ``x1/x2``, element-wise. Returns a scalar if - both ``x1`` and ``x2`` are scalars. + The quotient ``x1/x2``, element-wise. + $OUT_SCALAR_2 See Also -------- @@ -1050,7 +1078,8 @@ add_newdoc('numpy.core.umath', 'equal', Returns ------- out : ndarray or bool - Output array of bools, or a single bool if x1 and x2 are scalars. + Output array of bools. + $OUT_SCALAR_2 See Also -------- @@ -1081,8 +1110,9 @@ add_newdoc('numpy.core.umath', 'exp', Returns ------- - out : ndarray + out : ndarray or scalar Output array, element-wise exponential of `x`. + $OUT_SCALAR_1 See Also -------- @@ -1145,8 +1175,9 @@ add_newdoc('numpy.core.umath', 'exp2', Returns ------- - out : ndarray + out : ndarray or scalar Element-wise 2 to the power `x`. + $OUT_SCALAR_1 See Also -------- @@ -1177,8 +1208,9 @@ add_newdoc('numpy.core.umath', 'expm1', Returns ------- - out : ndarray + out : ndarray or scalar Element-wise exponential minus one: ``out = exp(x) - 1``. + $OUT_SCALAR_1 See Also -------- @@ -1222,6 +1254,7 @@ add_newdoc('numpy.core.umath', 'fabs', ------- y : ndarray or scalar The absolute values of `x`, the returned values are always floats. + $OUT_SCALAR_1 See Also -------- @@ -1253,6 +1286,7 @@ add_newdoc('numpy.core.umath', 'floor', ------- y : ndarray or scalar The floor of each element in `x`. + $OUT_SCALAR_1 See Also -------- @@ -1291,7 +1325,7 @@ add_newdoc('numpy.core.umath', 'floor_divide', ------- y : ndarray y = floor(`x1`/`x2`) - + $OUT_SCALAR_2 See Also -------- @@ -1322,15 +1356,16 @@ add_newdoc('numpy.core.umath', 'fmod', Parameters ---------- x1 : array_like - Dividend. + Dividend. x2 : array_like - Divisor. + Divisor. $PARAMS Returns ------- y : array_like - The remainder of the division of `x1` by `x2`. + The remainder of the division of `x1` by `x2`. + $OUT_SCALAR_2 See Also -------- @@ -1381,7 +1416,8 @@ add_newdoc('numpy.core.umath', 'greater', Returns ------- out : bool or ndarray of bool - Array of bools, or a single bool if `x1` and `x2` are scalars. + Array of bools. + $OUT_SCALAR_2 See Also @@ -1417,7 +1453,8 @@ add_newdoc('numpy.core.umath', 'greater_equal', Returns ------- out : bool or ndarray of bool - Array of bools, or a single bool if `x1` and `x2` are scalars. + Array of bools. + $OUT_SCALAR_2 See Also -------- @@ -1449,6 +1486,7 @@ add_newdoc('numpy.core.umath', 'hypot', ------- z : ndarray The hypotenuse of the triangle(s). + $OUT_SCALAR_2 Examples -------- @@ -1489,8 +1527,9 @@ add_newdoc('numpy.core.umath', 'invert', Returns ------- - out : array_like + out : ndarray or scalar Result. + $OUT_SCALAR_1 See Also -------- @@ -1562,15 +1601,9 @@ add_newdoc('numpy.core.umath', 'isfinite', Returns ------- y : ndarray, bool - For scalar input, the result is a new boolean with value True - if the input is finite; otherwise the value is False (input is - either positive infinity, negative infinity or Not a Number). - - For array input, the result is a boolean array with the same - dimensions as the input and the values are True if the - corresponding element of the input is finite; otherwise the values - are False (element is either positive infinity, negative infinity - or Not a Number). + True where ``x`` is not positive infinity, negative infinity, + or NaN; false otherwise. + $OUT_SCALAR_1 See Also -------- @@ -1628,18 +1661,8 @@ add_newdoc('numpy.core.umath', 'isinf', Returns ------- y : bool (scalar) or boolean ndarray - For scalar input, the result is a new boolean with value True if - the input is positive or negative infinity; otherwise the value is - False. - - For array input, the result is a boolean array with the same shape - as the input and the values are True where the corresponding - element of the input is positive or negative infinity; elsewhere - the values are False. If a second argument was supplied the result - is stored there. If the type of that array is a numeric type the - result is represented as zeros and ones, if the type is boolean - then as False and True, respectively. The return value `y` is then - a reference to that array. + True where ``x`` is positive or negative infinity, false otherwise. + $OUT_SCALAR_1 See Also -------- @@ -1687,13 +1710,8 @@ add_newdoc('numpy.core.umath', 'isnan', Returns ------- y : ndarray or bool - For scalar input, the result is a new boolean with value True if - the input is NaN; otherwise the value is False. - - For array input, the result is a boolean array of the same - dimensions as the input and the values are True if the - corresponding element of the input is NaN; otherwise the values are - False. + True where ``x`` is NaN, false otherwise. + $OUT_SCALAR_1 See Also -------- @@ -1728,13 +1746,8 @@ add_newdoc('numpy.core.umath', 'isnat', Returns ------- y : ndarray or bool - For scalar input, the result is a new boolean with value True if - the input is NaT; otherwise the value is False. - - For array input, the result is a boolean array of the same - dimensions as the input and the values are True if the - corresponding element of the input is NaT; otherwise the values are - False. + True where ``x`` is NaT, false otherwise. + $OUT_SCALAR_1 See Also -------- @@ -1771,6 +1784,7 @@ add_newdoc('numpy.core.umath', 'left_shift', ------- out : array of integer type Return `x1` with bits shifted `x2` times to the left. + $OUT_SCALAR_2 See Also -------- @@ -1807,7 +1821,8 @@ add_newdoc('numpy.core.umath', 'less', Returns ------- out : bool or ndarray of bool - Array of bools, or a single bool if `x1` and `x2` are scalars. + Array of bools. + $OUT_SCALAR_2 See Also -------- @@ -1835,7 +1850,8 @@ add_newdoc('numpy.core.umath', 'less_equal', Returns ------- out : bool or ndarray of bool - Array of bools, or a single bool if `x1` and `x2` are scalars. + Array of bools. + $OUT_SCALAR_2 See Also -------- @@ -1866,6 +1882,7 @@ add_newdoc('numpy.core.umath', 'log', ------- y : ndarray The natural logarithm of `x`, element-wise. + $OUT_SCALAR_1 See Also -------- @@ -1914,6 +1931,7 @@ add_newdoc('numpy.core.umath', 'log10', y : ndarray The logarithm to the base 10 of `x`, element-wise. NaNs are returned where x is negative. + $OUT_SCALAR_1 See Also -------- @@ -1961,6 +1979,7 @@ add_newdoc('numpy.core.umath', 'log2', ------- y : ndarray Base-2 logarithm of `x`. + $OUT_SCALAR_1 See Also -------- @@ -2015,6 +2034,7 @@ add_newdoc('numpy.core.umath', 'logaddexp', ------- result : ndarray Logarithm of ``exp(x1) + exp(x2)``. + $OUT_SCALAR_2 See Also -------- @@ -2056,6 +2076,7 @@ add_newdoc('numpy.core.umath', 'logaddexp2', ------- result : ndarray Base-2 logarithm of ``2**x1 + 2**x2``. + $OUT_SCALAR_2 See Also -------- @@ -2093,6 +2114,7 @@ add_newdoc('numpy.core.umath', 'log1p', ------- y : ndarray Natural logarithm of `1 + x`, element-wise. + $OUT_SCALAR_1 See Also -------- @@ -2146,6 +2168,7 @@ add_newdoc('numpy.core.umath', 'logical_and', y : ndarray or bool Boolean result with the same shape as `x1` and `x2` of the logical AND operation on corresponding elements of `x1` and `x2`. + $OUT_SCALAR_2 See Also -------- @@ -2180,6 +2203,7 @@ add_newdoc('numpy.core.umath', 'logical_not', y : bool or ndarray of bool Boolean result with the same shape as `x` of the NOT operation on elements of `x`. + $OUT_SCALAR_1 See Also -------- @@ -2214,6 +2238,7 @@ add_newdoc('numpy.core.umath', 'logical_or', y : ndarray or bool Boolean result with the same shape as `x1` and `x2` of the logical OR operation on elements of `x1` and `x2`. + $OUT_SCALAR_2 See Also -------- @@ -2250,6 +2275,7 @@ add_newdoc('numpy.core.umath', 'logical_xor', Boolean result of the logical XOR operation applied to the elements of `x1` and `x2`; the shape is determined by whether or not broadcasting of one or both arrays was required. + $OUT_SCALAR_2 See Also -------- @@ -2295,8 +2321,8 @@ add_newdoc('numpy.core.umath', 'maximum', Returns ------- y : ndarray or scalar - The maximum of `x1` and `x2`, element-wise. Returns scalar if - both `x1` and `x2` are scalars. + The maximum of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 See Also -------- @@ -2354,8 +2380,8 @@ add_newdoc('numpy.core.umath', 'minimum', Returns ------- y : ndarray or scalar - The minimum of `x1` and `x2`, element-wise. Returns scalar if - both `x1` and `x2` are scalars. + The minimum of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 See Also -------- @@ -2413,8 +2439,8 @@ add_newdoc('numpy.core.umath', 'fmax', Returns ------- y : ndarray or scalar - The maximum of `x1` and `x2`, element-wise. Returns scalar if - both `x1` and `x2` are scalars. + The maximum of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 See Also -------- @@ -2471,8 +2497,8 @@ add_newdoc('numpy.core.umath', 'fmin', Returns ------- y : ndarray or scalar - The minimum of `x1` and `x2`, element-wise. Returns scalar if - both `x1` and `x2` are scalars. + The minimum of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 See Also -------- @@ -2525,8 +2551,10 @@ add_newdoc('numpy.core.umath', 'modf', ------- y1 : ndarray Fractional part of `x`. + $OUT_SCALAR_1 y2 : ndarray Integral part of `x`. + $OUT_SCALAR_1 Notes ----- @@ -2560,7 +2588,8 @@ add_newdoc('numpy.core.umath', 'multiply', ------- y : ndarray The product of `x1` and `x2`, element-wise. Returns a scalar if - both `x1` and `x2` are scalars. + both `x1` and `x2` are scalars. + $OUT_SCALAR_2 Notes ----- @@ -2594,6 +2623,7 @@ add_newdoc('numpy.core.umath', 'negative', ------- y : ndarray or scalar Returned array or scalar: `y = -x`. + $OUT_SCALAR_1 Examples -------- @@ -2617,6 +2647,7 @@ add_newdoc('numpy.core.umath', 'positive', ------- y : ndarray or scalar Returned array or scalar: `y = +x`. + $OUT_SCALAR_1 Notes ----- @@ -2632,14 +2663,15 @@ add_newdoc('numpy.core.umath', 'not_equal', Parameters ---------- x1, x2 : array_like - Input arrays. + Input arrays. $PARAMS Returns ------- not_equal : ndarray bool, scalar bool - For each element in `x1, x2`, return True if `x1` is not equal - to `x2` and False otherwise. + For each element in `x1, x2`, return True if `x1` is not equal + to `x2` and False otherwise. + $OUT_SCALAR_2 See Also @@ -2688,6 +2720,7 @@ add_newdoc('numpy.core.umath', 'power', ------- y : ndarray The bases in `x1` raised to the exponents in `x2`. + $OUT_SCALAR_2 See Also -------- @@ -2746,6 +2779,7 @@ add_newdoc('numpy.core.umath', 'float_power', ------- y : ndarray The bases in `x1` raised to the exponents in `x2`. + $OUT_SCALAR_2 See Also -------- @@ -2793,6 +2827,7 @@ add_newdoc('numpy.core.umath', 'radians', ------- y : ndarray The corresponding radian values. + $OUT_SCALAR_1 See Also -------- @@ -2829,6 +2864,7 @@ add_newdoc('numpy.core.umath', 'deg2rad', ------- y : ndarray The corresponding angle in radians. + $OUT_SCALAR_1 See Also -------- @@ -2864,6 +2900,7 @@ add_newdoc('numpy.core.umath', 'reciprocal', ------- y : ndarray Return array. + $OUT_SCALAR_1 Notes ----- @@ -2914,7 +2951,7 @@ add_newdoc('numpy.core.umath', 'remainder', ------- y : ndarray The element-wise remainder of the quotient ``floor_divide(x1, x2)``. - Returns a scalar if both `x1` and `x2` are scalars. + $OUT_SCALAR_2 See Also -------- @@ -2959,8 +2996,10 @@ add_newdoc('numpy.core.umath', 'divmod', ------- out1 : ndarray Element-wise quotient resulting from floor division. + $OUT_SCALAR_2 out2 : ndarray Element-wise remainder from floor division. + $OUT_SCALAR_2 See Also -------- @@ -2996,6 +3035,7 @@ add_newdoc('numpy.core.umath', 'right_shift', ------- out : ndarray, int Return `x1` with bits shifted `x2` times to the right. + $OUT_SCALAR_2 See Also -------- @@ -3031,6 +3071,7 @@ add_newdoc('numpy.core.umath', 'rint', ------- out : ndarray or scalar Output array is same shape and type as `x`. + $OUT_SCALAR_1 See Also -------- @@ -3059,13 +3100,14 @@ add_newdoc('numpy.core.umath', 'sign', Parameters ---------- x : array_like - Input values. + Input values. $PARAMS Returns ------- y : ndarray - The sign of `x`. + The sign of `x`. + $OUT_SCALAR_1 Notes ----- @@ -3098,6 +3140,7 @@ add_newdoc('numpy.core.umath', 'signbit', ------- result : ndarray of bool Output array, or reference to `out` if that was supplied. + $OUT_SCALAR_1 Examples -------- @@ -3126,8 +3169,9 @@ add_newdoc('numpy.core.umath', 'copysign', Returns ------- - out : array_like + out : ndarray or scalar The values of `x1` with the sign of `x2`. + $OUT_SCALAR_2 Examples -------- @@ -3159,8 +3203,9 @@ add_newdoc('numpy.core.umath', 'nextafter', Returns ------- - out : array_like + out : ndarray or scalar The next representable values of `x1` in the direction of `x2`. + $OUT_SCALAR_2 Examples -------- @@ -3184,8 +3229,9 @@ add_newdoc('numpy.core.umath', 'spacing', Returns ------- - out : array_like - The spacing of values of `x1`. + out : ndarray or scalar + The spacing of values of `x`. + $OUT_SCALAR_1 Notes ----- @@ -3217,6 +3263,7 @@ add_newdoc('numpy.core.umath', 'sin', ------- y : array_like The sine of each element of x. + $OUT_SCALAR_1 See Also -------- @@ -3277,6 +3324,7 @@ add_newdoc('numpy.core.umath', 'sinh', ------- y : ndarray The corresponding hyperbolic sine values. + $OUT_SCALAR_1 Notes ----- @@ -3330,6 +3378,7 @@ add_newdoc('numpy.core.umath', 'sqrt', negative reals are calculated). If all of the elements in `x` are real, so is `y`, with negative elements returning ``nan``. If `out` was provided, `y` is a reference to it. + $OUT_SCALAR_1 See Also -------- @@ -3374,6 +3423,7 @@ add_newdoc('numpy.core.umath', 'cbrt', An array of the same shape as `x`, containing the cube cube-root of each element in `x`. If `out` was provided, `y` is a reference to it. + $OUT_SCALAR_1 Examples @@ -3395,9 +3445,9 @@ add_newdoc('numpy.core.umath', 'square', Returns ------- - out : ndarray + out : ndarray or scalar Element-wise `x*x`, of the same shape and dtype as `x`. - Returns scalar if `x` is a scalar. + $OUT_SCALAR_1 See Also -------- @@ -3425,8 +3475,8 @@ add_newdoc('numpy.core.umath', 'subtract', Returns ------- y : ndarray - The difference of `x1` and `x2`, element-wise. Returns a scalar if - both `x1` and `x2` are scalars. + The difference of `x1` and `x2`, element-wise. + $OUT_SCALAR_2 Notes ----- @@ -3455,13 +3505,14 @@ add_newdoc('numpy.core.umath', 'tan', Parameters ---------- x : array_like - Input array. + Input array. $PARAMS Returns ------- y : ndarray - The corresponding tangent values. + The corresponding tangent values. + $OUT_SCALAR_1 Notes ----- @@ -3509,6 +3560,7 @@ add_newdoc('numpy.core.umath', 'tanh', ------- y : ndarray The corresponding hyperbolic tangent values. + $OUT_SCALAR_1 Notes ----- @@ -3561,8 +3613,8 @@ add_newdoc('numpy.core.umath', 'true_divide', Returns ------- - out : ndarray - Result is scalar if both inputs are scalar, ndarray otherwise. + out : ndarray or scalar + $OUT_SCALAR_2 Notes ----- @@ -3614,9 +3666,12 @@ add_newdoc('numpy.core.umath', 'frexp', Returns ------- - (mantissa, exponent) : tuple of ndarrays, (float, int) - `mantissa` is a float array with values between -1 and 1. - `exponent` is an int array which represents the exponent of 2. + mantissa : ndarray + Floating values between -1 and 1. + $OUT_SCALAR_1 + exponent : ndarray + Integer exponents of 2. + $OUT_SCALAR_1 See Also -------- @@ -3659,6 +3714,7 @@ add_newdoc('numpy.core.umath', 'ldexp', ------- y : ndarray or scalar The result of ``x1 * 2**x2``. + $OUT_SCALAR_2 See Also -------- @@ -3695,6 +3751,7 @@ add_newdoc('numpy.core.umath', 'gcd', ------- y : ndarray or scalar The greatest common divisor of the absolute value of the inputs + $OUT_SCALAR_2 See Also -------- @@ -3724,6 +3781,7 @@ add_newdoc('numpy.core.umath', 'lcm', ------- y : ndarray or scalar The lowest common multiple of the absolute value of the inputs + $OUT_SCALAR_2 See Also -------- diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py index e81a4a039..5f1aadbf5 100644 --- a/numpy/core/fromnumeric.py +++ b/numpy/core/fromnumeric.py @@ -764,7 +764,7 @@ def sort(a, axis=-1, kind='quicksort', order=None): axis : int or None, optional Axis along which to sort. If None, the array is flattened before sorting. The default is -1, which sorts along the last axis. - kind : {'quicksort', 'mergesort', 'heapsort'}, optional + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional Sorting algorithm. Default is 'quicksort'. order : str or list of str, optional When `a` is an array with fields defined, this argument specifies @@ -794,13 +794,13 @@ def sort(a, axis=-1, kind='quicksort', order=None): order. The three available algorithms have the following properties: - =========== ======= ============= ============ ======= - kind speed worst case work space stable - =========== ======= ============= ============ ======= + =========== ======= ============= ============ ======== + kind speed worst case work space stable + =========== ======= ============= ============ ======== 'quicksort' 1 O(n^2) 0 no 'mergesort' 2 O(n*log(n)) ~n/2 yes 'heapsort' 3 O(n*log(n)) 0 no - =========== ======= ============= ============ ======= + =========== ======= ============= ============ ======== All the sort algorithms make temporary copies of the data when sorting along any but the last axis. Consequently, sorting along @@ -829,6 +829,10 @@ def sort(a, axis=-1, kind='quicksort', order=None): heapsort when it does not make enough progress. This makes its worst case O(n*log(n)). + 'stable' automatically choses the best stable sorting algorithm + for the data type being sorted. It is currently mapped to + merge sort. + Examples -------- >>> a = np.array([[1,4],[3,1]]) @@ -886,7 +890,7 @@ def argsort(a, axis=-1, kind='quicksort', order=None): axis : int or None, optional Axis along which to sort. The default is -1 (the last axis). If None, the flattened array is used. - kind : {'quicksort', 'mergesort', 'heapsort'}, optional + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional Sorting algorithm. order : str or list of str, optional When `a` is an array with fields defined, this argument specifies diff --git a/numpy/core/include/numpy/npy_common.h b/numpy/core/include/numpy/npy_common.h index b7634a930..5faff4385 100644 --- a/numpy/core/include/numpy/npy_common.h +++ b/numpy/core/include/numpy/npy_common.h @@ -101,22 +101,6 @@ #endif #endif -#ifdef HAVE___BUILTIN_CPU_SUPPORTS - #ifdef HAVE_ATTRIBUTE_TARGET_AVX2 - #define NPY_CPU_SUPPORTS_AVX2 __builtin_cpu_supports("avx2") - #else - #define NPY_CPU_SUPPORTS_AVX2 0 - #endif - #ifdef HAVE_ATTRIBUTE_TARGET_AVX - #define NPY_CPU_SUPPORTS_AVX __builtin_cpu_supports("avx") - #else - #define NPY_CPU_SUPPORTS_AVX 0 - #endif -#else - #define NPY_CPU_SUPPORTS_AVX 0 - #define NPY_CPU_SUPPORTS_AVX2 0 -#endif - #if defined(_MSC_VER) #define NPY_INLINE __inline #elif defined(__GNUC__) diff --git a/numpy/core/include/numpy/npy_cpu.h b/numpy/core/include/numpy/npy_cpu.h index 84653ea18..106ffa450 100644 --- a/numpy/core/include/numpy/npy_cpu.h +++ b/numpy/core/include/numpy/npy_cpu.h @@ -17,6 +17,7 @@ * NPY_CPU_SH_BE * NPY_CPU_ARCEL * NPY_CPU_ARCEB + * NPY_CPU_RISCV64 */ #ifndef _NPY_CPUARCH_H_ #define _NPY_CPUARCH_H_ @@ -82,6 +83,8 @@ #define NPY_CPU_ARCEL #elif defined(__arc__) && defined(__BIG_ENDIAN__) #define NPY_CPU_ARCEB +#elif defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 + #define NPY_CPU_RISCV64 #else #error Unknown CPU, please report this to numpy maintainers with \ information about your platform (OS, CPU and compiler) diff --git a/numpy/core/include/numpy/npy_endian.h b/numpy/core/include/numpy/npy_endian.h index 1a42121db..649bdb0a6 100644 --- a/numpy/core/include/numpy/npy_endian.h +++ b/numpy/core/include/numpy/npy_endian.h @@ -46,7 +46,8 @@ || defined(NPY_CPU_SH_LE) \ || defined(NPY_CPU_MIPSEL) \ || defined(NPY_CPU_PPC64LE) \ - || defined(NPY_CPU_ARCEL) + || defined(NPY_CPU_ARCEL) \ + || defined(NPY_CPU_RISCV64) #define NPY_BYTE_ORDER NPY_LITTLE_ENDIAN #elif defined(NPY_CPU_PPC) \ || defined(NPY_CPU_SPARC) \ diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py index aa5059180..d154206c5 100644 --- a/numpy/core/numeric.py +++ b/numpy/core/numeric.py @@ -1,7 +1,7 @@ from __future__ import division, absolute_import, print_function try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/core/setup.py b/numpy/core/setup.py index d519e0eb8..15f6e1522 100644 --- a/numpy/core/setup.py +++ b/numpy/core/setup.py @@ -888,6 +888,7 @@ def configuration(parent_package='',top_path=None): join('src', 'umath', 'loops.c.src'), join('src', 'umath', 'ufunc_object.c'), join('src', 'umath', 'extobj.c'), + join('src', 'umath', 'cpuid.c'), join('src', 'umath', 'scalarmath.c.src'), join('src', 'umath', 'ufunc_type_resolution.c'), join('src', 'umath', 'override.c'), diff --git a/numpy/core/setup_common.py b/numpy/core/setup_common.py index 1fe953910..f36d61f55 100644 --- a/numpy/core/setup_common.py +++ b/numpy/core/setup_common.py @@ -146,6 +146,7 @@ OPTIONAL_INTRINSICS = [("__builtin_isnan", '5.'), "stdio.h", "LINK_AVX"), ("__asm__ volatile", '"vpand %ymm1, %ymm2, %ymm3"', "stdio.h", "LINK_AVX2"), + ("__asm__ volatile", '"xgetbv"', "stdio.h", "XGETBV"), ] # function attributes diff --git a/numpy/core/src/multiarray/conversion_utils.c b/numpy/core/src/multiarray/conversion_utils.c index b39834266..7e92e5991 100644 --- a/numpy/core/src/multiarray/conversion_utils.c +++ b/numpy/core/src/multiarray/conversion_utils.c @@ -419,6 +419,10 @@ PyArray_SortkindConverter(PyObject *obj, NPY_SORTKIND *sortkind) else if (str[0] == 'm' || str[0] == 'M') { *sortkind = NPY_MERGESORT; } + else if (str[0] == 's' || str[0] == 'S') { + /* mergesort is the only stable sorting method in numpy */ + *sortkind = NPY_MERGESORT; + } else { PyErr_Format(PyExc_ValueError, "%s is an unrecognized kind of sort", diff --git a/numpy/core/src/multiarray/datetime_strings.c b/numpy/core/src/multiarray/datetime_strings.c index 96cb66b95..4f9d8fa41 100644 --- a/numpy/core/src/multiarray/datetime_strings.c +++ b/numpy/core/src/multiarray/datetime_strings.c @@ -374,7 +374,7 @@ parse_iso_8601_datetime(char *str, Py_ssize_t len, } /* Leading '-' sign for negative year */ - if (*substr == '-') { + if (*substr == '-' || *substr == '+') { ++substr; --sublen; } diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src index e101c3779..9df635dee 100644 --- a/numpy/core/src/multiarray/scalartypes.c.src +++ b/numpy/core/src/multiarray/scalartypes.c.src @@ -4174,6 +4174,37 @@ initialize_casting_tables(void) } } +#ifndef NPY_PY3K +/* + * In python2, the `float` and `complex` types still implement the obsolete + * "tp_print" method, which uses CPython's float-printing routines to print the + * float. Numpy's float_/cfloat inherit from Python float/complex, but + * override its tp_repr and tp_str methods. In order to avoid an inconsistency + * with the inherited tp_print, we need to override it too. + * + * In python3 the tp_print method is reserved/unused. + */ +static int +doubletype_print(PyObject *o, FILE *fp, int flags) +{ + int ret; + PyObject *to_print; + if (flags & Py_PRINT_RAW) { + to_print = PyObject_Str(o); + } + else { + to_print = PyObject_Repr(o); + } + + if (to_print == NULL) { + return -1; + } + + ret = PyObject_Print(to_print, fp, flags); + Py_DECREF(to_print); + return ret; +} +#endif static PyNumberMethods longdoubletype_as_number; static PyNumberMethods clongdoubletype_as_number; @@ -4226,6 +4257,12 @@ initialize_numeric_types(void) /**end repeat**/ +#ifndef NPY_PY3K + PyDoubleArrType_Type.tp_print = &doubletype_print; + PyCDoubleArrType_Type.tp_print = &doubletype_print; +#endif + + PyBoolArrType_Type.tp_as_number->nb_index = (unaryfunc)bool_index; PyStringArrType_Type.tp_alloc = NULL; diff --git a/numpy/core/src/umath/cpuid.c b/numpy/core/src/umath/cpuid.c new file mode 100644 index 000000000..912d51eeb --- /dev/null +++ b/numpy/core/src/umath/cpuid.c @@ -0,0 +1,56 @@ +#define _UMATHMODULE +#define NPY_NO_DEPRECATED_API NPY_API_VERSION + +#include <Python.h> + +#include "npy_config.h" + +#define PY_ARRAY_UNIQUE_SYMBOL _npy_umathmodule_ARRAY_API +#define NO_IMPORT_ARRAY + +#include "cpuid.h" + +#define XCR_XFEATURE_ENABLED_MASK 0x0 +#define XSTATE_SSE 0x2 +#define XSTATE_YMM 0x4 + +/* + * verify the OS supports avx instructions + * it can be disabled in some OS, e.g. with the nosavex boot option of linux + */ +static NPY_INLINE +int os_avx_support(void) +{ +#if HAVE_XGETBV + /* + * use bytes for xgetbv to avoid issues with compiler not knowing the + * instruction + */ + unsigned int eax, edx; + unsigned int ecx = XCR_XFEATURE_ENABLED_MASK; + __asm__("xgetbv" : "=a" (eax), "=d" (edx) : "c" (ecx)); + return (eax & (XSTATE_SSE | XSTATE_YMM)) == (XSTATE_SSE | XSTATE_YMM); +#else + return 0; +#endif +} + + +/* + * Primitive cpu feature detect function + * Currently only supports checking for avx on gcc compatible compilers. + */ +NPY_NO_EXPORT int +npy_cpu_supports(const char * feature) +{ +#ifdef HAVE___BUILTIN_CPU_SUPPORTS + if (strcmp(feature, "avx2") == 0) { + return __builtin_cpu_supports("avx2") && os_avx_support(); + } + else if (strcmp(feature, "avx") == 0) { + return __builtin_cpu_supports("avx") && os_avx_support(); + } +#endif + + return 0; +} diff --git a/numpy/core/src/umath/cpuid.h b/numpy/core/src/umath/cpuid.h new file mode 100644 index 000000000..33702ed41 --- /dev/null +++ b/numpy/core/src/umath/cpuid.h @@ -0,0 +1,9 @@ +#ifndef _NPY_PRIVATE__CPUID_H_ +#define _NPY_PRIVATE__CPUID_H_ + +#include <numpy/ndarraytypes.h> /* for NPY_NO_EXPORT */ + +NPY_NO_EXPORT int +npy_cpu_supports(const char * feature); + +#endif diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py index 638994aee..ba291737a 100644 --- a/numpy/core/tests/test_datetime.py +++ b/numpy/core/tests/test_datetime.py @@ -1255,12 +1255,19 @@ class TestDateTime(object): # Allow space instead of 'T' between date and time assert_equal(np.array(['1980-02-29T01:02:03'], np.dtype('M8[s]')), np.array(['1980-02-29 01:02:03'], np.dtype('M8[s]'))) + # Allow positive years + assert_equal(np.array(['+1980-02-29T01:02:03'], np.dtype('M8[s]')), + np.array(['+1980-02-29 01:02:03'], np.dtype('M8[s]'))) # Allow negative years assert_equal(np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')), np.array(['-1980-02-29 01:02:03'], np.dtype('M8[s]'))) # UTC specifier with assert_warns(DeprecationWarning): assert_equal( + np.array(['+1980-02-29T01:02:03'], np.dtype('M8[s]')), + np.array(['+1980-02-29 01:02:03Z'], np.dtype('M8[s]'))) + with assert_warns(DeprecationWarning): + assert_equal( np.array(['-1980-02-29T01:02:03'], np.dtype('M8[s]')), np.array(['-1980-02-29 01:02:03Z'], np.dtype('M8[s]'))) # Time zone offset diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py index 00e2a1e31..d861da4b6 100644 --- a/numpy/core/tests/test_multiarray.py +++ b/numpy/core/tests/test_multiarray.py @@ -1,7 +1,7 @@ from __future__ import division, absolute_import, print_function try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/core/tests/test_records.py b/numpy/core/tests/test_records.py index 32ce5dc42..8e261d226 100644 --- a/numpy/core/tests/test_records.py +++ b/numpy/core/tests/test_records.py @@ -2,7 +2,7 @@ from __future__ import division, absolute_import, print_function import sys try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/core/tests/test_scalarprint.py b/numpy/core/tests/test_scalarprint.py index d57f1a890..47cd2a40a 100644 --- a/numpy/core/tests/test_scalarprint.py +++ b/numpy/core/tests/test_scalarprint.py @@ -6,6 +6,7 @@ from __future__ import division, absolute_import, print_function import numpy as np from numpy.testing import assert_, assert_equal, run_module_suite +import sys, tempfile class TestRealScalars(object): @@ -45,6 +46,22 @@ class TestRealScalars(object): check(1e15) check(1e16) + def test_py2_float_print(self): + # gh-10753 + # In python2, the python float type implements an obsolte method + # tp_print, which overrides tp_repr and tp_str when using "print" to + # output to a "real file" (ie, not a StringIO). Make sure we don't + # inherit it. + x = np.double(0.1999999999999) + with tempfile.TemporaryFile('r+t') as f: + print(x, file=f) + f.seek(0) + output = f.read() + assert_equal(output, str(x) + '\n') + # In python2 the value float('0.1999999999999') prints with reduced + # precision as '0.2', but we want numpy's np.double('0.1999999999999') + # to print the unique value, '0.1999999999999'. + def test_dragon4(self): # these tests are adapted from Ryan Juckett's dragon4 implementation, # see dragon4.c for details. diff --git a/numpy/core/tests/test_ufunc.py b/numpy/core/tests/test_ufunc.py index b690c8132..576ecaf0d 100644 --- a/numpy/core/tests/test_ufunc.py +++ b/numpy/core/tests/test_ufunc.py @@ -626,7 +626,7 @@ class TestUfunc(object): assert_array_equal(c, (a * b).sum(0)) c = in1d(a, b, axes=[0, 2]) assert_array_equal(c, (a.transpose(1, 2, 0) * b).sum(-1)) - # Check errors for inproperly constructed axes arguments. + # Check errors for improperly constructed axes arguments. # should have list. assert_raises(TypeError, in1d, a, b, axes=-1) # needs enough elements @@ -671,7 +671,7 @@ class TestUfunc(object): d = mm(a, b, out=c, axes=[(-2, -1), (-2, -1), (3, 0)]) assert_(c is d) assert_array_equal(c, np.matmul(a, b).transpose(3, 0, 1, 2)) - # Check errors for inproperly constructed axes arguments. + # Check errors for improperly constructed axes arguments. # wrong argument assert_raises(TypeError, mm, a, b, axis=1) # axes should be list diff --git a/numpy/distutils/__init__.py b/numpy/distutils/__init__.py index 0450334ff..d5921b399 100644 --- a/numpy/distutils/__init__.py +++ b/numpy/distutils/__init__.py @@ -17,7 +17,7 @@ try: # Normally numpy is installed if the above import works, but an interrupted # in-place build could also have left a __config__.py. In that case the # next import may still fail, so keep it inside the try block. - from numpy.testing.nosetester import _numpy_tester + from numpy.testing import _numpy_tester test = _numpy_tester().test except ImportError: pass @@ -26,7 +26,7 @@ except ImportError: def customized_fcompiler(plat=None, compiler=None): from numpy.distutils.fcompiler import new_fcompiler c = new_fcompiler(plat=plat, compiler=compiler) - c.customize() + c.customize() return c def customized_ccompiler(plat=None, compiler=None): diff --git a/numpy/doc/subclassing.py b/numpy/doc/subclassing.py index 467e31cea..3be3d94b3 100644 --- a/numpy/doc/subclassing.py +++ b/numpy/doc/subclassing.py @@ -562,7 +562,7 @@ pass on to ``A.__array_ufunc__``, the ``super`` call in ``A`` would go to Prior to numpy 1.13, the behaviour of ufuncs could only be tuned using ``__array_wrap__`` and ``__array_prepare__``. These two allowed one to -change the output type of a ufunc, but, in constrast to +change the output type of a ufunc, but, in contrast to ``__array_ufunc__``, did not allow one to make any changes to the inputs. It is hoped to eventually deprecate these, but ``__array_wrap__`` is also used by other numpy functions and methods, such as ``squeeze``, so at the diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py index 250c4322b..86cc45b42 100644 --- a/numpy/f2py/__init__.py +++ b/numpy/f2py/__init__.py @@ -71,4 +71,3 @@ def compile(source, from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/f2py/crackfortran.py b/numpy/f2py/crackfortran.py index dc560f98e..19ce8c145 100755 --- a/numpy/f2py/crackfortran.py +++ b/numpy/f2py/crackfortran.py @@ -612,7 +612,7 @@ multilinepattern = re.compile( def split_by_unquoted(line, characters): """ Splits the line into (line[:i], line[i:]), - where i is the index of first occurence of one of the characters + where i is the index of first occurrence of one of the characters not within quotes, or len(line) if no such index exists """ assert not (set('"\'') & set(characters)), "cannot split by unquoted quotes" diff --git a/numpy/fft/__init__.py b/numpy/fft/__init__.py index 72d61a728..d1716bd4b 100644 --- a/numpy/fft/__init__.py +++ b/numpy/fft/__init__.py @@ -8,4 +8,3 @@ from .helper import * from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/lib/__init__.py b/numpy/lib/__init__.py index cc05232a2..0c2e6dfab 100644 --- a/numpy/lib/__init__.py +++ b/numpy/lib/__init__.py @@ -48,4 +48,3 @@ __all__ += histograms.__all__ from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/lib/function_base.py b/numpy/lib/function_base.py index 9ccbfafa2..8440be52e 100644 --- a/numpy/lib/function_base.py +++ b/numpy/lib/function_base.py @@ -184,21 +184,18 @@ def flip(m, axis): >>> A array([[[0, 1], [2, 3]], - [[4, 5], [6, 7]]]) >>> flip(A, 0) array([[[4, 5], [6, 7]], - [[0, 1], [2, 3]]]) >>> flip(A, 1) array([[[2, 3], [0, 1]], - [[6, 7], [4, 5]]]) diff --git a/numpy/linalg/__init__.py b/numpy/linalg/__init__.py index 2537926c5..1510a8448 100644 --- a/numpy/linalg/__init__.py +++ b/numpy/linalg/__init__.py @@ -52,4 +52,3 @@ from .linalg import * from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/ma/__init__.py b/numpy/ma/__init__.py index fbefc47a4..0689f2932 100644 --- a/numpy/ma/__init__.py +++ b/numpy/ma/__init__.py @@ -53,4 +53,3 @@ __all__ += extras.__all__ from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/ma/core.py b/numpy/ma/core.py index 5f53dfdae..91cf8ed0f 100644 --- a/numpy/ma/core.py +++ b/numpy/ma/core.py @@ -5317,7 +5317,7 @@ class MaskedArray(ndarray): originally intended. Until then, the axis should be given explicitly when ``arr.ndim > 1``, to avoid a FutureWarning. - kind : {'quicksort', 'mergesort', 'heapsort'}, optional + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional Sorting algorithm. order : list, optional When `a` is an array with fields defined, this argument specifies @@ -5468,7 +5468,7 @@ class MaskedArray(ndarray): axis : int, optional Axis along which to sort. If None, the array is flattened before sorting. The default is -1, which sorts along the last axis. - kind : {'quicksort', 'mergesort', 'heapsort'}, optional + kind : {'quicksort', 'mergesort', 'heapsort', 'stable'}, optional Sorting algorithm. Default is 'quicksort'. order : list, optional When `a` is a structured array, this argument specifies which fields diff --git a/numpy/ma/tests/test_core.py b/numpy/ma/tests/test_core.py index 4c6bb2b42..ff1e087b5 100644 --- a/numpy/ma/tests/test_core.py +++ b/numpy/ma/tests/test_core.py @@ -3200,6 +3200,12 @@ class TestMaskedArrayMethods(object): assert_equal(sortedx._data, [1, 2, -2, -1, 0]) assert_equal(sortedx._mask, [1, 1, 0, 0, 0]) + def test_stable_sort(self): + x = array([1, 2, 3, 1, 2, 3], dtype=np.uint8) + expected = array([0, 3, 1, 4, 2, 5]) + computed = argsort(x, kind='stable') + assert_equal(computed, expected) + def test_argsort_matches_sort(self): x = array([1, 4, 2, 3], mask=[0, 1, 0, 0], dtype=np.uint8) diff --git a/numpy/matrixlib/__init__.py b/numpy/matrixlib/__init__.py index 11dce2928..95713580d 100644 --- a/numpy/matrixlib/__init__.py +++ b/numpy/matrixlib/__init__.py @@ -9,4 +9,3 @@ __all__ = defmatrix.__all__ from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/matrixlib/tests/test_defmatrix.py b/numpy/matrixlib/tests/test_defmatrix.py index 9575f9c8a..d5435a1a3 100644 --- a/numpy/matrixlib/tests/test_defmatrix.py +++ b/numpy/matrixlib/tests/test_defmatrix.py @@ -1,7 +1,7 @@ from __future__ import division, absolute_import, print_function try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/polynomial/__init__.py b/numpy/polynomial/__init__.py index ae5b1f078..f7cbc19b0 100644 --- a/numpy/polynomial/__init__.py +++ b/numpy/polynomial/__init__.py @@ -24,4 +24,3 @@ from .laguerre import Laguerre from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/random/__init__.py b/numpy/random/__init__.py index 869818a22..409f50ec0 100644 --- a/numpy/random/__init__.py +++ b/numpy/random/__init__.py @@ -119,4 +119,3 @@ def __RandomState_ctor(): from numpy.testing import _numpy_tester test = _numpy_tester().test -bench = _numpy_tester().bench diff --git a/numpy/testing/__init__.py b/numpy/testing/__init__.py index 9485b455e..f4970b06b 100644 --- a/numpy/testing/__init__.py +++ b/numpy/testing/__init__.py @@ -9,7 +9,12 @@ from __future__ import division, absolute_import, print_function from unittest import TestCase -from . import decorators as dec -from .nosetester import run_module_suite, NoseTester as Tester, _numpy_tester -from .utils import * +from ._private.utils import * +from ._private import decorators as dec +from ._private.nosetester import ( + run_module_suite, NoseTester as Tester, _numpy_tester, + ) + +__all__ = _private.utils.__all__ + ['TestCase', 'run_module_suite'] + test = _numpy_tester().test diff --git a/numpy/testing/nose_tools/__init__.py b/numpy/testing/_private/__init__.py index e69de29bb..e69de29bb 100644 --- a/numpy/testing/nose_tools/__init__.py +++ b/numpy/testing/_private/__init__.py diff --git a/numpy/testing/nose_tools/decorators.py b/numpy/testing/_private/decorators.py index dee832404..60d3f968f 100644 --- a/numpy/testing/nose_tools/decorators.py +++ b/numpy/testing/_private/decorators.py @@ -16,7 +16,7 @@ function name, setup and teardown functions and so on - see from __future__ import division, absolute_import, print_function try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/testing/nose_tools/noseclasses.py b/numpy/testing/_private/noseclasses.py index 08dec0ca9..08dec0ca9 100644 --- a/numpy/testing/nose_tools/noseclasses.py +++ b/numpy/testing/_private/noseclasses.py diff --git a/numpy/testing/nose_tools/nosetester.py b/numpy/testing/_private/nosetester.py index c2cf58377..c2cf58377 100644 --- a/numpy/testing/nose_tools/nosetester.py +++ b/numpy/testing/_private/nosetester.py diff --git a/numpy/testing/nose_tools/parameterized.py b/numpy/testing/_private/parameterized.py index 53e67517d..53e67517d 100644 --- a/numpy/testing/nose_tools/parameterized.py +++ b/numpy/testing/_private/parameterized.py diff --git a/numpy/testing/_private/pytesttester.py b/numpy/testing/_private/pytesttester.py new file mode 100644 index 000000000..6a92a52fd --- /dev/null +++ b/numpy/testing/_private/pytesttester.py @@ -0,0 +1,175 @@ +""" +Pytest test running. + +This module implements the ``test()`` function for NumPy modules. The usual +boiler plate for doing that is to put the following in the module +``__init__.py`` file:: + + from numpy.testing import PytestTester + test = PytestTester(__name__).test + del PytestTester + + +Warnings filtering and other runtime settings should be dealt with in the +``pytest.ini`` file in the numpy repo root. The behavior of the test depends on +whether or not that file is found as follows: + +* ``pytest.ini`` is present (develop mode) + All warnings except those explicily filtered out are raised as error. +* ``pytest.ini`` is absent (release mode) + DeprecationWarnings and PendingDeprecationWarnings are ignored, other + warnings are passed through. + +In practice, tests run from the numpy repo are run in develop mode. That +includes the standard ``python runtests.py`` invocation. + +""" +from __future__ import division, absolute_import, print_function + +import sys +import os + +__all__ = ['PytestTester'] + + +def _show_numpy_info(): + import numpy as np + + print("NumPy version %s" % np.__version__) + relaxed_strides = np.ones((10, 1), order="C").flags.f_contiguous + print("NumPy relaxed strides checking option:", relaxed_strides) + + +class PytestTester(object): + """ + Pytest test runner. + + This class is made available in ``numpy.testing``, and a test function + is typically added to a package's __init__.py like so:: + + from numpy.testing import PytestTester + test = PytestTester(__name__).test + del PytestTester + + Calling this test function finds and runs all tests associated with the + module and all its sub-modules. + + Attributes + ---------- + module_name : str + Full path to the package to test. + + Parameters + ---------- + module_name : module name + The name of the module to test. + + """ + def __init__(self, module_name): + self.module_name = module_name + + def test(self, label='fast', verbose=1, extra_argv=None, + doctests=False, coverage=False, timer=0, tests=None): + """ + Run tests for module using pytest. + + Parameters + ---------- + label : {'fast', 'full'}, optional + Identifies the tests to run. When set to 'fast', tests decorated + with `pytest.mark.slow` are skipped, when 'full', the slow marker + is ignored. + verbose : int, optional + Verbosity value for test outputs, in the range 1-3. Default is 1. + extra_argv : list, optional + List with any extra arguments to pass to pytests. + doctests : bool, optional + .. note:: Not supported + coverage : bool, optional + If True, report coverage of NumPy code. Default is False. + Requires installation of (pip) pytest-cov. + timer : int, optional + If > 0, report the time of the slowest `timer` tests. Default is 0. + + tests : test or list of tests + Tests to be executed with pytest '--pyargs' + + Returns + ------- + result : bool + Return True on success, false otherwise. + + Notes + ----- + Each NumPy module exposes `test` in its namespace to run all tests for it. + For example, to run all tests for numpy.lib: + + >>> np.lib.test() #doctest: +SKIP + + Examples + -------- + >>> result = np.lib.test() #doctest: +SKIP + Running unit tests for numpy.lib + ... + Ran 976 tests in 3.933s + + OK + + >>> result.errors #doctest: +SKIP + [] + >>> result.knownfail #doctest: +SKIP + [] + + """ + import pytest + + #FIXME This is no longer needed? Assume it was for use in tests. + # cap verbosity at 3, which is equivalent to the pytest '-vv' option + #from . import utils + #verbose = min(int(verbose), 3) + #utils.verbose = verbose + # + + module = sys.modules[self.module_name] + module_path = os.path.abspath(module.__path__[0]) + + # setup the pytest arguments + pytest_args = ['-l'] + + if doctests: + raise ValueError("Doctests not supported") + + if extra_argv: + pytest_args += list(extra_argv) + + if verbose > 1: + pytest_args += ["-" + "v"*(verbose - 1)] + else: + pytest_args += ["-q"] + + if coverage: + pytest_args += ["--cov=" + module_path] + + if label == "fast": + pytest_args += ["-m", "not slow"] + elif label != "full": + pytest_args += ["-m", label] + + if timer > 0: + pytest_args += ["--durations=%s" % timer] + + if tests is None: + tests = [self.module_name] + + pytest_args += ['--pyargs'] + list(tests) + + + # run tests. + _show_numpy_info() + + try: + code = pytest.main(pytest_args) + except SystemExit as exc: + code = exc.code + + return code == 0 diff --git a/numpy/testing/nose_tools/utils.py b/numpy/testing/_private/utils.py index 507ecb1e2..507ecb1e2 100644 --- a/numpy/testing/nose_tools/utils.py +++ b/numpy/testing/_private/utils.py diff --git a/numpy/testing/decorators.py b/numpy/testing/decorators.py index 21bcdd798..1988afd29 100644 --- a/numpy/testing/decorators.py +++ b/numpy/testing/decorators.py @@ -3,6 +3,9 @@ Back compatibility decorators module. It will import the appropriate set of tools """ -import os +import warnings -from .nose_tools.decorators import * +warnings.warn("Import from numpy.testing, not numpy.testing.decorators", + ImportWarning) + +from ._private.decorators import * diff --git a/numpy/testing/noseclasses.py b/numpy/testing/noseclasses.py index 144c4e7e4..dde62e825 100644 --- a/numpy/testing/noseclasses.py +++ b/numpy/testing/noseclasses.py @@ -2,4 +2,10 @@ Back compatibility noseclasses module. It will import the appropriate set of tools """ -from .nose_tools.noseclasses import *
\ No newline at end of file +import warnings + +warnings.warn("Import from numpy.testing, not numpy.testing.noseclasses", + ImportWarning) + +from ._private.noseclasses import * + diff --git a/numpy/testing/nosetester.py b/numpy/testing/nosetester.py index 949fae03e..772bff305 100644 --- a/numpy/testing/nosetester.py +++ b/numpy/testing/nosetester.py @@ -3,10 +3,12 @@ Back compatibility nosetester module. It will import the appropriate set of tools """ -import os +import warnings -from .nose_tools.nosetester import * +warnings.warn("Import from numpy.testing, not numpy.testing.nosetester", + ImportWarning) +from ._private.nosetester import * __all__ = ['get_package_name', 'run_module_suite', 'NoseTester', '_numpy_tester', 'get_package_name', 'import_nose', diff --git a/numpy/testing/pytest_tools/decorators.py b/numpy/testing/pytest_tools/decorators.py index f8addb9c8..e72b1eb0b 100644 --- a/numpy/testing/pytest_tools/decorators.py +++ b/numpy/testing/pytest_tools/decorators.py @@ -13,7 +13,7 @@ function name, setup and teardown functions and so on. from __future__ import division, absolute_import, print_function try: - # Accessing collections abstact classes from collections + # Accessing collections abstract classes from collections # has been deprecated since Python 3.3 import collections.abc as collections_abc except ImportError: diff --git a/numpy/testing/setup.py b/numpy/testing/setup.py index 5a0f977d9..b00e5e029 100755 --- a/numpy/testing/setup.py +++ b/numpy/testing/setup.py @@ -6,7 +6,7 @@ def configuration(parent_package='',top_path=None): from numpy.distutils.misc_util import Configuration config = Configuration('testing', parent_package, top_path) - config.add_subpackage('nose_tools') + config.add_subpackage('_private') config.add_subpackage('pytest_tools') config.add_data_dir('tests') return config diff --git a/numpy/testing/utils.py b/numpy/testing/utils.py index a0218c4e6..3cd89e639 100644 --- a/numpy/testing/utils.py +++ b/numpy/testing/utils.py @@ -3,9 +3,12 @@ Back compatibility utils module. It will import the appropriate set of tools """ -import os +import warnings -from .nose_tools.utils import * +warnings.warn("Import from numpy.testing, not numpy.testing.utils", + ImportWarning) + +from ._private.utils import * __all__ = [ 'assert_equal', 'assert_almost_equal', 'assert_approx_equal', diff --git a/pytest.ini b/pytest.ini index d3d7142d4..e901beb8c 100644 --- a/pytest.ini +++ b/pytest.ini @@ -1,9 +1,21 @@ [pytest] +addopts = -l -q norecursedirs = doc tools numpy/linalg/lapack_lite numpy/core/code_generators doctest_optionflags = NORMALIZE_WHITESPACE -testpaths = numpy +filterwarnings = + error +# Filter out annoying import messages. + ignore:Not importing directory + ignore:numpy.dtype size changed + ignore:numpy.ufunc size changed +# Ignore python2.7 -3 warnings + ignore:sys\.exc_clear\(\) not supported in 3\.x:DeprecationWarning + ignore:in 3\.x, __setslice__:DeprecationWarning + ignore:in 3\.x, __getslice__:DeprecationWarning + ignore:buffer\(\) not supported in 3\.x:DeprecationWarning + ignore:CObject type is not supported in 3\.x:DeprecationWarning + ignore:comparing unequal types not supported in 3\.x:DeprecationWarning + ignore:the commands module has been removed in Python 3\.0:DeprecationWarning env = PYTHONHASHSEED=0 - -# addopts = --doctest-modules --ignore=numpy/f2py/__main__.py --ignore=numpy/core/cversions.py --ignore=numpy/ma/core.py --ignore=numpy/ma/version.py --ignore=numpy/testing/utils.py --ignore=numpy/testing/decorators.py |