summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/release/1.17.0-notes.rst21
-rw-r--r--doc/source/dev/development_environment.rst4
-rw-r--r--doc/source/f2py/run_main_session.dat2
-rw-r--r--doc/source/f2py/usage.rst29
-rw-r--r--numpy/core/_exceptions.py100
-rw-r--r--numpy/core/include/numpy/ndarraytypes.h20
-rw-r--r--numpy/core/numeric.py10
-rw-r--r--numpy/core/records.py5
-rw-r--r--numpy/core/src/multiarray/compiled_base.c2
-rw-r--r--numpy/core/src/multiarray/ctors.c5
-rw-r--r--numpy/core/src/umath/ufunc_type_resolution.c199
-rw-r--r--numpy/core/tests/test_errstate.py8
-rw-r--r--numpy/core/tests/test_multiarray.py56
-rw-r--r--numpy/distutils/fcompiler/pg.py6
-rw-r--r--numpy/f2py/__init__.py22
-rwxr-xr-xnumpy/f2py/f2py2e.py21
-rw-r--r--numpy/f2py/tests/test_compile_function.py17
-rw-r--r--numpy/lib/nanfunctions.py27
-rw-r--r--numpy/lib/tests/test_nanfunctions.py28
19 files changed, 466 insertions, 116 deletions
diff --git a/doc/release/1.17.0-notes.rst b/doc/release/1.17.0-notes.rst
index 5d13fd5ff..4bdb812d7 100644
--- a/doc/release/1.17.0-notes.rst
+++ b/doc/release/1.17.0-notes.rst
@@ -86,6 +86,27 @@ new function, ``np.ctypeslib.as_ctypes`` now supports a much wider range of
array types, including structures, booleans, and integers of non-native
endianness.
+`numpy.errstate` is now also function decorator
+-----------------------------------------------
+
+Currently, if you have a function like::
+
+ def foo():
+ pass
+
+and you want to wrap the whole thing in `errstate`, you have to rewrite it like so::
+
+ def foo():
+ with np.errstate(...):
+ pass
+
+but with this change, you can do::
+
+ @np.errstate(...)
+ def foo():
+ pass
+
+thereby saving a level of indentation
Changes
=======
diff --git a/doc/source/dev/development_environment.rst b/doc/source/dev/development_environment.rst
index aa4326f63..f9b438bfd 100644
--- a/doc/source/dev/development_environment.rst
+++ b/doc/source/dev/development_environment.rst
@@ -8,7 +8,9 @@ Recommended development setup
Since NumPy contains parts written in C and Cython that need to be
compiled before use, make sure you have the necessary compilers and Python
-development headers installed - see :ref:`building-from-source`.
+development headers installed - see :ref:`building-from-source`. Building
+NumPy as of version ``1.17`` requires a C99 compliant compiler. For
+some older compilers this may require ``export CFLAGS='-std=c99'``.
Having compiled code also means that importing NumPy from the development
sources needs some additional steps, which are explained below. For the rest
diff --git a/doc/source/f2py/run_main_session.dat b/doc/source/f2py/run_main_session.dat
index b9a7e1b0d..be6cacd22 100644
--- a/doc/source/f2py/run_main_session.dat
+++ b/doc/source/f2py/run_main_session.dat
@@ -8,7 +8,7 @@ Post-processing...
Building modules...
Building module "scalar"...
Wrote C/API module "scalar" to file "./scalarmodule.c"
->>> printr(r)
+>>> print(r)
{'scalar': {'h': ['/home/users/pearu/src_cvs/f2py/src/fortranobject.h'],
'csrc': ['./scalarmodule.c',
'/home/users/pearu/src_cvs/f2py/src/fortranobject.c']}}
diff --git a/doc/source/f2py/usage.rst b/doc/source/f2py/usage.rst
index 0f5068e0e..5043ec430 100644
--- a/doc/source/f2py/usage.rst
+++ b/doc/source/f2py/usage.rst
@@ -214,32 +214,7 @@ Python module ``numpy.f2py``
The current Python interface to the ``f2py`` module is not mature and
may change in the future.
-The following functions are provided by the ``numpy.f2py`` module:
-``run_main(<list>)``
- Equivalent to running::
+.. automodule:: numpy.f2py
+ :members:
- f2py <args>
-
- where ``<args>=string.join(<list>,' ')``, but in Python. Unless
- ``-h`` is used, this function returns a dictionary containing
- information on generated modules and their dependencies on source
- files. For example, the command ``f2py -m scalar scalar.f`` can be
- executed from Python as follows
-
- .. include:: run_main_session.dat
- :literal:
-
- You cannot build extension modules with this function, that is,
- using ``-c`` is not allowed. Use ``compile`` command instead, see
- below.
-
-``compile(source, modulename='untitled', extra_args='', verbose=1, source_fn=None)``
- Build extension module from Fortran 77 source string ``source``.
- Return 0 if successful.
- Note that this function actually calls ``f2py -c ..`` from shell to
- ensure safety of the current Python process.
- For example,
-
- .. include:: compile_session.dat
- :literal:
diff --git a/numpy/core/_exceptions.py b/numpy/core/_exceptions.py
new file mode 100644
index 000000000..5e0105beb
--- /dev/null
+++ b/numpy/core/_exceptions.py
@@ -0,0 +1,100 @@
+"""
+Various richly-typed exceptions, that also help us deal with string formatting
+in python where it's easier.
+
+By putting the formatting in `__str__`, we also avoid paying the cost for
+users who silence the exceptions.
+"""
+from numpy.core.overrides import set_module
+
+
+def _unpack_tuple(tup):
+ if len(tup) == 1:
+ return tup[0]
+ else:
+ return tup
+
+
+def _display_as_base(cls):
+ """
+ A decorator that makes an exception class look like its base.
+
+ We use this to hide subclasses that are implementation details - the user
+ should catch the base type, which is what the traceback will show them.
+
+ Classes decorated with this decorator are subject to removal without a
+ deprecation warning.
+ """
+ assert issubclass(cls, Exception)
+ cls.__name__ = cls.__base__.__name__
+ cls.__qualname__ = cls.__base__.__qualname__
+ return cls
+
+
+class UFuncTypeError(TypeError):
+ """ Base class for all ufunc exceptions """
+ def __init__(self, ufunc):
+ self.ufunc = ufunc
+
+
+@_display_as_base
+class _UFuncNoLoopError(UFuncTypeError):
+ """ Thrown when a ufunc loop cannot be found """
+ def __init__(self, ufunc, dtypes):
+ super().__init__(ufunc)
+ self.dtypes = tuple(dtypes)
+
+ def __str__(self):
+ return (
+ "ufunc {!r} did not contain a loop with signature matching types "
+ "{!r} -> {!r}"
+ ).format(
+ self.ufunc.__name__,
+ _unpack_tuple(self.dtypes[:self.ufunc.nin]),
+ _unpack_tuple(self.dtypes[self.ufunc.nin:])
+ )
+
+
+@_display_as_base
+class _UFuncCastingError(UFuncTypeError):
+ def __init__(self, ufunc, casting, from_, to):
+ super().__init__(ufunc)
+ self.casting = casting
+ self.from_ = from_
+ self.to = to
+
+
+@_display_as_base
+class _UFuncInputCastingError(_UFuncCastingError):
+ """ Thrown when a ufunc input cannot be casted """
+ def __init__(self, ufunc, casting, from_, to, i):
+ super().__init__(ufunc, casting, from_, to)
+ self.in_i = i
+
+ def __str__(self):
+ # only show the number if more than one input exists
+ i_str = "{} ".format(self.in_i) if self.ufunc.nin != 1 else ""
+ return (
+ "Cannot cast ufunc {!r} input {}from {!r} to {!r} with casting "
+ "rule {!r}"
+ ).format(
+ self.ufunc.__name__, i_str, self.from_, self.to, self.casting
+ )
+
+
+@_display_as_base
+class _UFuncOutputCastingError(_UFuncCastingError):
+ """ Thrown when a ufunc output cannot be casted """
+ def __init__(self, ufunc, casting, from_, to, i):
+ super().__init__(ufunc, casting, from_, to)
+ self.out_i = i
+
+ def __str__(self):
+ # only show the number if more than one output exists
+ i_str = "{} ".format(self.out_i) if self.ufunc.nout != 1 else ""
+ return (
+ "Cannot cast ufunc {!r} output {}from {!r} to {!r} with casting "
+ "rule {!r}"
+ ).format(
+ self.ufunc.__name__, i_str, self.from_, self.to, self.casting
+ )
diff --git a/numpy/core/include/numpy/ndarraytypes.h b/numpy/core/include/numpy/ndarraytypes.h
index b0b749c80..cfa1dba6a 100644
--- a/numpy/core/include/numpy/ndarraytypes.h
+++ b/numpy/core/include/numpy/ndarraytypes.h
@@ -950,12 +950,12 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
*/
-#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
-#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS(m, NPY_ARRAY_WRITEABLE)
-#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS(m, NPY_ARRAY_ALIGNED)
+#define PyArray_ISCONTIGUOUS(m) PyArray_CHKFLAGS((m), NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_ISWRITEABLE(m) PyArray_CHKFLAGS((m), NPY_ARRAY_WRITEABLE)
+#define PyArray_ISALIGNED(m) PyArray_CHKFLAGS((m), NPY_ARRAY_ALIGNED)
-#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_C_CONTIGUOUS)
-#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS(m, NPY_ARRAY_F_CONTIGUOUS)
+#define PyArray_IS_C_CONTIGUOUS(m) PyArray_CHKFLAGS((m), NPY_ARRAY_C_CONTIGUOUS)
+#define PyArray_IS_F_CONTIGUOUS(m) PyArray_CHKFLAGS((m), NPY_ARRAY_F_CONTIGUOUS)
/* the variable is used in some places, so always define it */
#define NPY_BEGIN_THREADS_DEF PyThreadState *_save=NULL;
@@ -965,15 +965,15 @@ typedef int (PyArray_FinalizeFunc)(PyArrayObject *, PyObject *);
#define NPY_BEGIN_THREADS do {_save = PyEval_SaveThread();} while (0);
#define NPY_END_THREADS do { if (_save) \
{ PyEval_RestoreThread(_save); _save = NULL;} } while (0);
-#define NPY_BEGIN_THREADS_THRESHOLDED(loop_size) do { if (loop_size > 500) \
+#define NPY_BEGIN_THREADS_THRESHOLDED(loop_size) do { if ((loop_size) > 500) \
{ _save = PyEval_SaveThread();} } while (0);
#define NPY_BEGIN_THREADS_DESCR(dtype) \
- do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI))) \
+ do {if (!(PyDataType_FLAGCHK((dtype), NPY_NEEDS_PYAPI))) \
NPY_BEGIN_THREADS;} while (0);
#define NPY_END_THREADS_DESCR(dtype) \
- do {if (!(PyDataType_FLAGCHK(dtype, NPY_NEEDS_PYAPI))) \
+ do {if (!(PyDataType_FLAGCHK((dtype), NPY_NEEDS_PYAPI))) \
NPY_END_THREADS; } while (0);
#define NPY_ALLOW_C_API_DEF PyGILState_STATE __save__;
@@ -1110,7 +1110,7 @@ struct PyArrayIterObject_tag {
/* Iterator API */
-#define PyArrayIter_Check(op) PyObject_TypeCheck(op, &PyArrayIter_Type)
+#define PyArrayIter_Check(op) PyObject_TypeCheck((op), &PyArrayIter_Type)
#define _PyAIT(it) ((PyArrayIterObject *)(it))
#define PyArray_ITER_RESET(it) do { \
@@ -1188,7 +1188,7 @@ struct PyArrayIterObject_tag {
#define PyArray_ITER_GOTO1D(it, ind) do { \
int __npy_i; \
- npy_intp __npy_ind = (npy_intp) (ind); \
+ npy_intp __npy_ind = (npy_intp)(ind); \
if (__npy_ind < 0) __npy_ind += _PyAIT(it)->size; \
_PyAIT(it)->index = __npy_ind; \
if (_PyAIT(it)->nd_m1 == 0) { \
diff --git a/numpy/core/numeric.py b/numpy/core/numeric.py
index 8a8efddf3..1b8f36c3e 100644
--- a/numpy/core/numeric.py
+++ b/numpy/core/numeric.py
@@ -12,6 +12,7 @@ import operator
import sys
import warnings
import numbers
+import contextlib
import numpy as np
from . import multiarray
@@ -2990,7 +2991,7 @@ _Unspecified = _unspecified()
@set_module('numpy')
-class errstate(object):
+class errstate(contextlib.ContextDecorator):
"""
errstate(**kwargs)
@@ -3000,7 +3001,12 @@ class errstate(object):
that context to execute with a known error handling behavior. Upon entering
the context the error handling is set with `seterr` and `seterrcall`, and
upon exiting it is reset to what it was before.
-
+
+ .. versionchanged:: 1.17.0
+ `errstate` is also usable as a function decorator, saving
+ a level of indentation if an entire function is wrapped.
+ See :py:class:`contextlib.ContextDecorator` for more information.
+
Parameters
----------
kwargs : {divide, over, under, invalid}
diff --git a/numpy/core/records.py b/numpy/core/records.py
index 4ea83accc..42aca5b60 100644
--- a/numpy/core/records.py
+++ b/numpy/core/records.py
@@ -721,7 +721,7 @@ def fromstring(datastring, dtype=None, shape=None, offset=0, formats=None,
a string"""
if dtype is None and formats is None:
- raise ValueError("Must have dtype= or formats=")
+ raise TypeError("fromstring() needs a 'dtype' or 'formats' argument")
if dtype is not None:
descr = sb.dtype(dtype)
@@ -768,6 +768,9 @@ def fromfile(fd, dtype=None, shape=None, offset=0, formats=None,
>>> r.shape
(10,)
"""
+
+ if dtype is None and formats is None:
+ raise TypeError("fromfile() needs a 'dtype' or 'formats' argument")
if (shape is None or shape == 0):
shape = (-1,)
diff --git a/numpy/core/src/multiarray/compiled_base.c b/numpy/core/src/multiarray/compiled_base.c
index 88924a860..625028bfb 100644
--- a/numpy/core/src/multiarray/compiled_base.c
+++ b/numpy/core/src/multiarray/compiled_base.c
@@ -328,6 +328,7 @@ arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
} else {
Py_XDECREF(values);
Py_XDECREF(mask);
+ PyArray_ResolveWritebackIfCopy(array);
Py_XDECREF(array);
Py_RETURN_NONE;
}
@@ -358,6 +359,7 @@ arr_insert(PyObject *NPY_UNUSED(self), PyObject *args, PyObject *kwdict)
fail:
Py_XDECREF(mask);
+ PyArray_ResolveWritebackIfCopy(array);
Py_XDECREF(array);
Py_XDECREF(values);
return NULL;
diff --git a/numpy/core/src/multiarray/ctors.c b/numpy/core/src/multiarray/ctors.c
index 63bf5377a..b2e329d45 100644
--- a/numpy/core/src/multiarray/ctors.c
+++ b/numpy/core/src/multiarray/ctors.c
@@ -2500,6 +2500,11 @@ PyArray_FromInterface(PyObject *origin)
&PyArray_Type, dtype,
n, dims, NULL, data,
dataflags, NULL, base);
+ /*
+ * Ref to dtype was stolen by PyArray_NewFromDescrAndBase
+ * Prevent DECREFing dtype in fail codepath by setting to NULL
+ */
+ dtype = NULL;
if (ret == NULL) {
goto fail;
}
diff --git a/numpy/core/src/umath/ufunc_type_resolution.c b/numpy/core/src/umath/ufunc_type_resolution.c
index c2d81fc5d..a4a59faa9 100644
--- a/numpy/core/src/umath/ufunc_type_resolution.c
+++ b/numpy/core/src/umath/ufunc_type_resolution.c
@@ -16,6 +16,7 @@
#include "npy_config.h"
#include "npy_pycompat.h"
+#include "npy_import.h"
#include "numpy/ufuncobject.h"
#include "ufunc_type_resolution.h"
@@ -27,6 +28,26 @@
#include "cblasfuncs.h"
#endif
+static PyObject *
+npy_casting_to_py_object(NPY_CASTING casting)
+{
+ switch (casting) {
+ case NPY_NO_CASTING:
+ return PyUString_FromString("no");
+ case NPY_EQUIV_CASTING:
+ return PyUString_FromString("equiv");
+ case NPY_SAFE_CASTING:
+ return PyUString_FromString("safe");
+ case NPY_SAME_KIND_CASTING:
+ return PyUString_FromString("same_kind");
+ case NPY_UNSAFE_CASTING:
+ return PyUString_FromString("unsafe");
+ default:
+ return PyInt_FromLong(casting);
+ }
+}
+
+
static const char *
npy_casting_to_string(NPY_CASTING casting)
{
@@ -46,6 +67,9 @@ npy_casting_to_string(NPY_CASTING casting)
}
}
+/**
+ * Always returns -1 to indicate the exception was raised, for convenience
+ */
static int
raise_binary_type_reso_error(PyUFuncObject *ufunc, PyArrayObject **operands) {
PyObject *errmsg;
@@ -63,6 +87,126 @@ raise_binary_type_reso_error(PyUFuncObject *ufunc, PyArrayObject **operands) {
return -1;
}
+/** Helper function to raise UFuncNoLoopError
+ * Always returns -1 to indicate the exception was raised, for convenience
+ */
+static int
+raise_no_loop_found_error(
+ PyUFuncObject *ufunc, PyArray_Descr **dtypes, npy_intp n_dtypes)
+{
+ static PyObject *exc_type = NULL;
+ PyObject *exc_value;
+ PyObject *dtypes_tup;
+ npy_intp i;
+
+ npy_cache_import(
+ "numpy.core._exceptions", "_UFuncNoLoopError",
+ &exc_type);
+ if (exc_type == NULL) {
+ return -1;
+ }
+
+ /* convert dtypes to a tuple */
+ dtypes_tup = PyTuple_New(n_dtypes);
+ if (dtypes_tup == NULL) {
+ return -1;
+ }
+ for (i = 0; i < n_dtypes; ++i) {
+ Py_INCREF(dtypes[i]);
+ PyTuple_SET_ITEM(dtypes_tup, i, (PyObject *)dtypes[i]);
+ }
+
+ /* produce an error object */
+ exc_value = PyTuple_Pack(2, ufunc, dtypes_tup);
+ Py_DECREF(dtypes_tup);
+ if (exc_value == NULL){
+ return -1;
+ }
+ PyErr_SetObject(exc_type, exc_value);
+ Py_DECREF(exc_value);
+
+ return -1;
+}
+
+static int
+raise_casting_error(
+ PyObject *exc_type,
+ PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArray_Descr *from,
+ PyArray_Descr *to,
+ npy_intp i)
+{
+ PyObject *exc_value;
+ PyObject *casting_value;
+
+ casting_value = npy_casting_to_py_object(casting);
+ if (casting_value == NULL) {
+ return -1;
+ }
+
+ exc_value = Py_BuildValue(
+ "ONOOi",
+ ufunc,
+ casting_value,
+ (PyObject *)from,
+ (PyObject *)to,
+ i
+ );
+ if (exc_value == NULL){
+ return -1;
+ }
+ PyErr_SetObject(exc_type, exc_value);
+ Py_DECREF(exc_value);
+
+ return -1;
+}
+
+/** Helper function to raise UFuncInputCastingError
+ * Always returns -1 to indicate the exception was raised, for convenience
+ */
+static int
+raise_input_casting_error(
+ PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArray_Descr *from,
+ PyArray_Descr *to,
+ npy_intp i)
+{
+ static PyObject *exc_type = NULL;
+ npy_cache_import(
+ "numpy.core._exceptions", "_UFuncInputCastingError",
+ &exc_type);
+ if (exc_type == NULL) {
+ return -1;
+ }
+
+ return raise_casting_error(exc_type, ufunc, casting, from, to, i);
+}
+
+
+/** Helper function to raise UFuncOutputCastingError
+ * Always returns -1 to indicate the exception was raised, for convenience
+ */
+static int
+raise_output_casting_error(
+ PyUFuncObject *ufunc,
+ NPY_CASTING casting,
+ PyArray_Descr *from,
+ PyArray_Descr *to,
+ npy_intp i)
+{
+ static PyObject *exc_type = NULL;
+ npy_cache_import(
+ "numpy.core._exceptions", "_UFuncOutputCastingError",
+ &exc_type);
+ if (exc_type == NULL) {
+ return -1;
+ }
+
+ return raise_casting_error(exc_type, ufunc, casting, from, to, i);
+}
+
/*UFUNC_API
*
@@ -79,45 +223,18 @@ PyUFunc_ValidateCasting(PyUFuncObject *ufunc,
PyArray_Descr **dtypes)
{
int i, nin = ufunc->nin, nop = nin + ufunc->nout;
- const char *ufunc_name = ufunc_get_name_cstr(ufunc);
for (i = 0; i < nop; ++i) {
if (i < nin) {
if (!PyArray_CanCastArrayTo(operands[i], dtypes[i], casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
- "input from ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtypes[i]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" with casting rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
- return -1;
+ return raise_input_casting_error(
+ ufunc, casting, PyArray_DESCR(operands[i]), dtypes[i], i);
}
} else if (operands[i] != NULL) {
if (!PyArray_CanCastTypeTo(dtypes[i],
PyArray_DESCR(operands[i]), casting)) {
- PyObject *errmsg;
- errmsg = PyUString_FromFormat("Cannot cast ufunc %s "
- "output from ", ufunc_name);
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtypes[i]));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromString(" to "));
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)PyArray_DESCR(operands[i])));
- PyUString_ConcatAndDel(&errmsg,
- PyUString_FromFormat(" with casting rule %s",
- npy_casting_to_string(casting)));
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
- return -1;
+ return raise_output_casting_error(
+ ufunc, casting, dtypes[i], PyArray_DESCR(operands[i]), i);
}
}
}
@@ -1382,12 +1499,8 @@ PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc,
{
int nargs = ufunc->nargs;
char *types;
- const char *ufunc_name;
- PyObject *errmsg;
int i, j;
- ufunc_name = ufunc_get_name_cstr(ufunc);
-
/*
* If there are user-loops search them first.
* TODO: There needs to be a loop selection acceleration structure,
@@ -1422,19 +1535,7 @@ PyUFunc_DefaultLegacyInnerLoopSelector(PyUFuncObject *ufunc,
types += nargs;
}
- errmsg = PyUString_FromFormat("ufunc '%s' did not contain a loop "
- "with signature matching types ", ufunc_name);
- for (i = 0; i < nargs; ++i) {
- PyUString_ConcatAndDel(&errmsg,
- PyObject_Repr((PyObject *)dtypes[i]));
- if (i < nargs - 1) {
- PyUString_ConcatAndDel(&errmsg, PyUString_FromString(" "));
- }
- }
- PyErr_SetObject(PyExc_TypeError, errmsg);
- Py_DECREF(errmsg);
-
- return -1;
+ return raise_no_loop_found_error(ufunc, dtypes, nargs);
}
typedef struct {
@@ -2251,7 +2352,7 @@ type_tuple_type_resolver(PyUFuncObject *self,
/* If no function was found, throw an error */
PyErr_Format(PyExc_TypeError,
- "No loop matching the specified signature and casting\n"
+ "No loop matching the specified signature and casting "
"was found for ufunc %s", ufunc_name);
return -1;
diff --git a/numpy/core/tests/test_errstate.py b/numpy/core/tests/test_errstate.py
index 670d485c1..0008c4cc8 100644
--- a/numpy/core/tests/test_errstate.py
+++ b/numpy/core/tests/test_errstate.py
@@ -39,3 +39,11 @@ class TestErrstate(object):
with np.errstate(call=None):
assert_(np.geterrcall() is None, 'call is not None')
assert_(np.geterrcall() is olderrcall, 'call is not olderrcall')
+
+ def test_errstate_decorator(self):
+ @np.errstate(all='ignore')
+ def foo():
+ a = -np.arange(3)
+ a // 0
+
+ foo()
diff --git a/numpy/core/tests/test_multiarray.py b/numpy/core/tests/test_multiarray.py
index 3dd45c5ce..241f8e48a 100644
--- a/numpy/core/tests/test_multiarray.py
+++ b/numpy/core/tests/test_multiarray.py
@@ -5920,7 +5920,7 @@ class TestMatmul(MatmulCommon):
assert_array_equal(out, tgt, err_msg=msg)
# test out with not allowed type cast (safe casting)
- msg = "Cannot cast ufunc matmul output"
+ msg = "Cannot cast ufunc .* output"
out = np.zeros((5, 2), dtype=np.int32)
assert_raises_regex(TypeError, msg, self.matmul, a, b, out=out)
@@ -7009,12 +7009,11 @@ class TestArrayAttributeDeletion(object):
assert_raises(AttributeError, delattr, a, s)
-def test_array_interface():
- # Test scalar coercion within the array interface
+class TestArrayInterface():
class Foo(object):
def __init__(self, value):
self.value = value
- self.iface = {'typestr': '=f8'}
+ self.iface = {'typestr': 'f8'}
def __float__(self):
return float(self.value)
@@ -7023,22 +7022,39 @@ def test_array_interface():
def __array_interface__(self):
return self.iface
+
f = Foo(0.5)
- assert_equal(np.array(f), 0.5)
- assert_equal(np.array([f]), [0.5])
- assert_equal(np.array([f, f]), [0.5, 0.5])
- assert_equal(np.array(f).dtype, np.dtype('=f8'))
- # Test various shape definitions
- f.iface['shape'] = ()
- assert_equal(np.array(f), 0.5)
- f.iface['shape'] = None
- assert_raises(TypeError, np.array, f)
- f.iface['shape'] = (1, 1)
- assert_equal(np.array(f), [[0.5]])
- f.iface['shape'] = (2,)
- assert_raises(ValueError, np.array, f)
-
- # test scalar with no shape
+
+ @pytest.mark.parametrize('val, iface, expected', [
+ (f, {}, 0.5),
+ ([f], {}, [0.5]),
+ ([f, f], {}, [0.5, 0.5]),
+ (f, {'shape': ()}, 0.5),
+ (f, {'shape': None}, TypeError),
+ (f, {'shape': (1, 1)}, [[0.5]]),
+ (f, {'shape': (2,)}, ValueError),
+ (f, {'strides': ()}, 0.5),
+ (f, {'strides': (2,)}, ValueError),
+ (f, {'strides': 16}, TypeError),
+ ])
+ def test_scalar_interface(self, val, iface, expected):
+ # Test scalar coercion within the array interface
+ self.f.iface = {'typestr': 'f8'}
+ self.f.iface.update(iface)
+ if HAS_REFCOUNT:
+ pre_cnt = sys.getrefcount(np.dtype('f8'))
+ if isinstance(expected, type):
+ assert_raises(expected, np.array, val)
+ else:
+ result = np.array(val)
+ assert_equal(np.array(val), expected)
+ assert result.dtype == 'f8'
+ del result
+ if HAS_REFCOUNT:
+ post_cnt = sys.getrefcount(np.dtype('f8'))
+ assert_equal(pre_cnt, post_cnt)
+
+def test_interface_no_shape():
class ArrayLike(object):
array = np.array(1)
__array_interface__ = array.__array_interface__
@@ -7713,6 +7729,8 @@ class TestWritebackIfCopy(object):
# uses arr_insert
np.place(a, a>2, [44, 55])
assert_equal(a, np.array([[0, 44], [1, 55], [2, 44]]))
+ # hit one of the failing paths
+ assert_raises(ValueError, np.place, a, a>20, [])
def test_put_noncontiguous(self):
a = np.arange(6).reshape(2,3).T # force non-c-contiguous
diff --git a/numpy/distutils/fcompiler/pg.py b/numpy/distutils/fcompiler/pg.py
index 99071800a..cdba0e39a 100644
--- a/numpy/distutils/fcompiler/pg.py
+++ b/numpy/distutils/fcompiler/pg.py
@@ -33,7 +33,7 @@ class PGroupFCompiler(FCompiler):
'compiler_f77': ["pgfortran"],
'compiler_fix': ["pgfortran", "-Mfixed"],
'compiler_f90': ["pgfortran"],
- 'linker_so': ["pgfortran", "-shared", "-fpic"],
+ 'linker_so': ["pgfortran"],
'archiver': ["ar", "-cr"],
'ranlib': ["ranlib"]
}
@@ -56,6 +56,10 @@ class PGroupFCompiler(FCompiler):
def get_flags_linker_so(self):
return ["-dynamic", '-undefined', 'dynamic_lookup']
+ else:
+ def get_flags_linker_so(self):
+ return ["-shared", '-fpic']
+
def runtime_library_dir_option(self, dir):
return '-R"%s"' % dir
diff --git a/numpy/f2py/__init__.py b/numpy/f2py/__init__.py
index 23a4b7c41..d146739bb 100644
--- a/numpy/f2py/__init__.py
+++ b/numpy/f2py/__init__.py
@@ -28,12 +28,16 @@ def compile(source,
extension='.f'
):
"""
- Build extension module from processing source with f2py.
+ Build extension module from a Fortran 77 source string with f2py.
Parameters
----------
- source : str
+ source : str or bytes
Fortran source of module / subroutine to compile
+
+ .. versionchanged:: 1.16.0
+ Accept str as well as bytes
+
modulename : str, optional
The name of the compiled python module
extra_args : str or list, optional
@@ -55,6 +59,16 @@ def compile(source,
.. versionadded:: 1.11.0
+ Returns
+ -------
+ result : int
+ 0 on success
+
+ Examples
+ --------
+ .. include:: compile_session.dat
+ :literal:
+
"""
import tempfile
import shlex
@@ -67,9 +81,11 @@ def compile(source,
else:
fname = source_fn
+ if not isinstance(source, str):
+ source = str(source, 'utf-8')
try:
with open(fname, 'w') as f:
- f.write(str(source))
+ f.write(source)
args = ['-c', '-m', modulename, f.name]
diff --git a/numpy/f2py/f2py2e.py b/numpy/f2py/f2py2e.py
index 8750ed0b3..47223151f 100755
--- a/numpy/f2py/f2py2e.py
+++ b/numpy/f2py/f2py2e.py
@@ -396,8 +396,25 @@ def dict_append(d_out, d_in):
def run_main(comline_list):
- """Run f2py as if string.join(comline_list,' ') is used as a command line.
- In case of using -h flag, return None.
+ """
+ Equivalent to running::
+
+ f2py <args>
+
+ where ``<args>=string.join(<list>,' ')``, but in Python. Unless
+ ``-h`` is used, this function returns a dictionary containing
+ information on generated modules and their dependencies on source
+ files. For example, the command ``f2py -m scalar scalar.f`` can be
+ executed from Python as follows
+
+ You cannot build extension modules with this function, that is,
+ using ``-c`` is not allowed. Use ``compile`` command instead
+
+ Examples
+ --------
+ .. include:: run_main_session.dat
+ :literal:
+
"""
crackfortran.reset_global_f2py_vars()
f2pydir = os.path.dirname(os.path.abspath(cfuncs.__file__))
diff --git a/numpy/f2py/tests/test_compile_function.py b/numpy/f2py/tests/test_compile_function.py
index 74e0804e2..36abf05f9 100644
--- a/numpy/f2py/tests/test_compile_function.py
+++ b/numpy/f2py/tests/test_compile_function.py
@@ -106,3 +106,20 @@ def test_f2py_init_compile_bad_cmd():
assert_equal(ret_val, 127)
finally:
sys.executable = temp
+
+
+@pytest.mark.parametrize('fsource',
+ ['program test_f2py\nend program test_f2py',
+ b'program test_f2py\nend program test_f2py',])
+def test_compile_from_strings(tmpdir, fsource):
+ # Make sure we can compile str and bytes gh-12796
+ cwd = os.getcwd()
+ try:
+ os.chdir(str(tmpdir))
+ ret_val = numpy.f2py.compile(
+ fsource,
+ modulename='test_compile_from_strings',
+ extension='.f90')
+ assert_equal(ret_val, 0)
+ finally:
+ os.chdir(cwd)
diff --git a/numpy/lib/nanfunctions.py b/numpy/lib/nanfunctions.py
index b3bf1880b..77c851fcf 100644
--- a/numpy/lib/nanfunctions.py
+++ b/numpy/lib/nanfunctions.py
@@ -40,6 +40,33 @@ __all__ = [
]
+def _nan_mask(a, out=None):
+ """
+ Parameters
+ ----------
+ a : array-like
+ Input array with at least 1 dimension.
+ out : ndarray, optional
+ Alternate output array in which to place the result. The default
+ is ``None``; if provided, it must have the same shape as the
+ expected output and will prevent the allocation of a new array.
+
+ Returns
+ -------
+ y : bool ndarray or True
+ A bool array where ``np.nan`` positions are marked with ``False``
+ and other positions are marked with ``True``. If the type of ``a``
+ is such that it can't possibly contain ``np.nan``, returns ``True``.
+ """
+ # we assume that a is an array for this private function
+
+ if a.dtype.kind not in 'fc':
+ return True
+
+ y = np.isnan(a, out=out)
+ y = np.invert(y, out=y)
+ return y
+
def _replace_nan(a, val):
"""
If `a` is of inexact type, make a copy of `a`, replace NaNs with
diff --git a/numpy/lib/tests/test_nanfunctions.py b/numpy/lib/tests/test_nanfunctions.py
index 504372faf..b7261c63f 100644
--- a/numpy/lib/tests/test_nanfunctions.py
+++ b/numpy/lib/tests/test_nanfunctions.py
@@ -1,8 +1,10 @@
from __future__ import division, absolute_import, print_function
import warnings
+import pytest
import numpy as np
+from numpy.lib.nanfunctions import _nan_mask
from numpy.testing import (
assert_, assert_equal, assert_almost_equal, assert_no_warnings,
assert_raises, assert_array_equal, suppress_warnings
@@ -925,3 +927,29 @@ class TestNanFunctions_Quantile(object):
p = p.tolist()
np.nanquantile(np.arange(100.), p, interpolation="midpoint")
assert_array_equal(p, p0)
+
+@pytest.mark.parametrize("arr, expected", [
+ # array of floats with some nans
+ (np.array([np.nan, 5.0, np.nan, np.inf]),
+ np.array([False, True, False, True])),
+ # int64 array that can't possibly have nans
+ (np.array([1, 5, 7, 9], dtype=np.int64),
+ True),
+ # bool array that can't possibly have nans
+ (np.array([False, True, False, True]),
+ True),
+ # 2-D complex array with nans
+ (np.array([[np.nan, 5.0],
+ [np.nan, np.inf]], dtype=np.complex64),
+ np.array([[False, True],
+ [False, True]])),
+ ])
+def test__nan_mask(arr, expected):
+ for out in [None, np.empty(arr.shape, dtype=np.bool_)]:
+ actual = _nan_mask(arr, out=out)
+ assert_equal(actual, expected)
+ # the above won't distinguish between True proper
+ # and an array of True values; we want True proper
+ # for types that can't possibly contain NaN
+ if type(expected) is not np.ndarray:
+ assert actual is True