summaryrefslogtreecommitdiff
path: root/numpy
diff options
context:
space:
mode:
Diffstat (limited to 'numpy')
-rw-r--r--numpy/core/_add_newdocs.py19
-rw-r--r--numpy/core/fromnumeric.py4
-rw-r--r--numpy/core/shape_base.py2
-rw-r--r--numpy/core/src/multiarray/convert_datatype.c8
-rw-r--r--numpy/core/src/multiarray/scalartypes.c.src7
-rw-r--r--numpy/core/src/npysort/npysort_common.h8
-rw-r--r--numpy/core/tests/test_datetime.py41
-rw-r--r--numpy/core/tests/test_regression.py20
-rw-r--r--numpy/core/tests/test_scalarmath.py12
-rw-r--r--numpy/distutils/misc_util.py7
-rw-r--r--numpy/lib/type_check.py10
-rw-r--r--numpy/linalg/linalg.py11
-rw-r--r--numpy/ma/core.py41
-rw-r--r--numpy/random/tests/test_extending.py6
14 files changed, 145 insertions, 51 deletions
diff --git a/numpy/core/_add_newdocs.py b/numpy/core/_add_newdocs.py
index 0225d12b9..2f1273904 100644
--- a/numpy/core/_add_newdocs.py
+++ b/numpy/core/_add_newdocs.py
@@ -3953,15 +3953,22 @@ add_newdoc('numpy.core.multiarray', 'ndarray', ('tolist',
Examples
--------
- For a 1D array, ``a.tolist()`` is almost the same as ``list(a)``:
+ For a 1D array, ``a.tolist()`` is almost the same as ``list(a)``,
+ except that ``tolist`` changes numpy scalars to Python scalars:
- >>> a = np.array([1, 2])
- >>> list(a)
+ >>> a = np.uint32([1, 2])
+ >>> a_list = list(a)
+ >>> a_list
[1, 2]
- >>> a.tolist()
+ >>> type(a_list[0])
+ <class 'numpy.uint32'>
+ >>> a_tolist = a.tolist()
+ >>> a_tolist
[1, 2]
+ >>> type(a_tolist[0])
+ <class 'int'>
- However, for a 2D array, ``tolist`` applies recursively:
+ Additionally, for a 2D array, ``tolist`` applies recursively:
>>> a = np.array([[1, 2], [3, 4]])
>>> list(a)
@@ -4246,7 +4253,7 @@ add_newdoc('numpy.core.umath', 'frompyfunc',
See Also
--------
- vectorize : evaluates pyfunc over input arrays using broadcasting rules of numpy
+ vectorize : Evaluates pyfunc over input arrays using broadcasting rules of numpy.
Notes
-----
diff --git a/numpy/core/fromnumeric.py b/numpy/core/fromnumeric.py
index 6e5f3dabf..d454480a8 100644
--- a/numpy/core/fromnumeric.py
+++ b/numpy/core/fromnumeric.py
@@ -944,6 +944,10 @@ def sort(a, axis=-1, kind=None, order=None):
'mergesort' and 'stable' are mapped to radix sort for integer data types. Radix sort is an
O(n) sort instead of O(n log n).
+ .. versionchanged:: 1.17.0
+
+ NaT now sorts to the end of arrays for consistency with NaN.
+
Examples
--------
>>> a = np.array([[1,4],[3,1]])
diff --git a/numpy/core/shape_base.py b/numpy/core/shape_base.py
index 369d956fb..31b1c20b9 100644
--- a/numpy/core/shape_base.py
+++ b/numpy/core/shape_base.py
@@ -575,7 +575,7 @@ def _concatenate_shapes(shapes, axis):
that was computed deeper in the recursion.
These are returned as tuples to ensure that they can quickly be added
- to existing slice tuple without creating a new tuple everytime.
+ to existing slice tuple without creating a new tuple every time.
"""
# Cache a result that will be reused.
diff --git a/numpy/core/src/multiarray/convert_datatype.c b/numpy/core/src/multiarray/convert_datatype.c
index 025c66013..4326448dc 100644
--- a/numpy/core/src/multiarray/convert_datatype.c
+++ b/numpy/core/src/multiarray/convert_datatype.c
@@ -877,7 +877,13 @@ PyArray_CanCastTypeTo(PyArray_Descr *from, PyArray_Descr *to,
from_order = dtype_kind_to_ordering(from->kind);
to_order = dtype_kind_to_ordering(to->kind);
- return from_order != -1 && from_order <= to_order;
+ if (to->kind == 'm') {
+ /* both types being timedelta is already handled before. */
+ int integer_order = dtype_kind_to_ordering('i');
+ return (from_order != -1) && (from_order <= integer_order);
+ }
+
+ return (from_order != -1) && (from_order <= to_order);
}
else {
return 0;
diff --git a/numpy/core/src/multiarray/scalartypes.c.src b/numpy/core/src/multiarray/scalartypes.c.src
index 32d712e0c..5da7f7738 100644
--- a/numpy/core/src/multiarray/scalartypes.c.src
+++ b/numpy/core/src/multiarray/scalartypes.c.src
@@ -4060,8 +4060,11 @@ initialize_casting_tables(void)
_npy_can_cast_safely_table[_FROM_NUM][NPY_STRING] = 1;
_npy_can_cast_safely_table[_FROM_NUM][NPY_UNICODE] = 1;
- /* Allow casts from any integer to the TIMEDELTA type */
-#if @from_isint@ || @from_isuint@
+#if @from_isint@ && NPY_SIZEOF_TIMEDELTA >= _FROM_BSIZE
+ /* Allow casts from smaller or equal signed integers to the TIMEDELTA type */
+ _npy_can_cast_safely_table[_FROM_NUM][NPY_TIMEDELTA] = 1;
+#elif @from_isuint@ && NPY_SIZEOF_TIMEDELTA > _FROM_BSIZE
+ /* Allow casts from smaller unsigned integers to the TIMEDELTA type */
_npy_can_cast_safely_table[_FROM_NUM][NPY_TIMEDELTA] = 1;
#endif
diff --git a/numpy/core/src/npysort/npysort_common.h b/numpy/core/src/npysort/npysort_common.h
index 5fd03b96f..30c0d47f3 100644
--- a/numpy/core/src/npysort/npysort_common.h
+++ b/numpy/core/src/npysort/npysort_common.h
@@ -329,6 +329,14 @@ UNICODE_LT(const npy_ucs4 *s1, const npy_ucs4 *s2, size_t len)
NPY_INLINE static int
DATETIME_LT(npy_datetime a, npy_datetime b)
{
+ if (a == NPY_DATETIME_NAT) {
+ return 0;
+ }
+
+ if (b == NPY_DATETIME_NAT) {
+ return 1;
+ }
+
return a < b;
}
diff --git a/numpy/core/tests/test_datetime.py b/numpy/core/tests/test_datetime.py
index e8ffbbb9d..41b84a69f 100644
--- a/numpy/core/tests/test_datetime.py
+++ b/numpy/core/tests/test_datetime.py
@@ -75,6 +75,15 @@ class TestDateTime(object):
# Can cast safely/same_kind from integer to timedelta
assert_(np.can_cast('i8', 'm8', casting='same_kind'))
assert_(np.can_cast('i8', 'm8', casting='safe'))
+ assert_(np.can_cast('i4', 'm8', casting='same_kind'))
+ assert_(np.can_cast('i4', 'm8', casting='safe'))
+ assert_(np.can_cast('u4', 'm8', casting='same_kind'))
+ assert_(np.can_cast('u4', 'm8', casting='safe'))
+
+ # Cannot cast safely from unsigned integer of the same size, which
+ # could overflow
+ assert_(np.can_cast('u8', 'm8', casting='same_kind'))
+ assert_(not np.can_cast('u8', 'm8', casting='safe'))
# Cannot cast safely/same_kind from float to timedelta
assert_(not np.can_cast('f4', 'm8', casting='same_kind'))
@@ -136,6 +145,38 @@ class TestDateTime(object):
assert_(np.datetime64('NaT') != np.datetime64('NaT', 'us'))
assert_(np.datetime64('NaT', 'us') != np.datetime64('NaT'))
+
+
+ @pytest.mark.parametrize("size", [
+ 3, 21, 217, 1000])
+ def test_nat_argsort_stability(self, size):
+ # NaT < NaT should be False internally for
+ # sort stability
+ expected = np.arange(size)
+ arr = np.tile(np.datetime64('NaT'), size)
+ assert_equal(np.argsort(arr, kind='mergesort'), expected)
+
+ @pytest.mark.parametrize("arr, expected", [
+ # the example provided in gh-12629
+ (np.array(['NaT', 1, 2, 3], dtype='M8[ns]'),
+ np.array([1, 2, 3, 'NaT'], dtype='M8[ns]')),
+ # multiple NaTs
+ (np.array(['NaT', 9, 'NaT', -707], dtype='M8[s]'),
+ np.array([-707, 9, 'NaT', 'NaT'], dtype='M8[s]')),
+ # this sort explores another code path for NaT
+ (np.array([1, -2, 3, 'NaT'], dtype='M8[ns]'),
+ np.array([-2, 1, 3, 'NaT'], dtype='M8[ns]')),
+ # 2-D array
+ (np.array([[51, -220, 'NaT'],
+ [-17, 'NaT', -90]], dtype='M8[us]'),
+ np.array([[-220, 51, 'NaT'],
+ [-90, -17, 'NaT']], dtype='M8[us]')),
+ ])
+ def test_sort_nat(self, arr, expected):
+ # fix for gh-12629; NaT sorting to end of array
+ arr.sort()
+ assert_equal(arr, expected)
+
def test_datetime_scalar_construction(self):
# Construct with different units
assert_equal(np.datetime64('1950-03-12', 'D'),
diff --git a/numpy/core/tests/test_regression.py b/numpy/core/tests/test_regression.py
index d5de0f2b2..3880b1394 100644
--- a/numpy/core/tests/test_regression.py
+++ b/numpy/core/tests/test_regression.py
@@ -2484,26 +2484,6 @@ class TestRegression(object):
np.array([T()])
- def test_2d__array__shape(self):
- class T(object):
- def __array__(self):
- return np.ndarray(shape=(0,0))
-
- # Make sure __array__ is used instead of Sequence methods.
- def __iter__(self):
- return iter([])
-
- def __getitem__(self, idx):
- raise AssertionError("__getitem__ was called")
-
- def __len__(self):
- return 0
-
-
- t = T()
- #gh-13659, would raise in broadcasting [x=t for x in result]
- np.array([t])
-
@pytest.mark.skipif(sys.maxsize < 2 ** 31 + 1, reason='overflows 32-bit python')
@pytest.mark.skipif(sys.platform == 'win32' and sys.version_info[:2] < (3, 8),
reason='overflows on windows, fixed in bpo-16865')
diff --git a/numpy/core/tests/test_scalarmath.py b/numpy/core/tests/test_scalarmath.py
index 854df5590..c84380cd9 100644
--- a/numpy/core/tests/test_scalarmath.py
+++ b/numpy/core/tests/test_scalarmath.py
@@ -11,7 +11,7 @@ import numpy as np
from numpy.testing import (
assert_, assert_equal, assert_raises, assert_almost_equal,
assert_array_equal, IS_PYPY, suppress_warnings, _gen_alignment_data,
- assert_warns
+ assert_warns, assert_raises_regex,
)
types = [np.bool_, np.byte, np.ubyte, np.short, np.ushort, np.intc, np.uintc,
@@ -293,6 +293,16 @@ class TestModulus(object):
rem = operator.mod(finf, fone)
assert_(np.isnan(rem), 'dt: %s' % dt)
+ def test_inplace_floordiv_handling(self):
+ # issue gh-12927
+ # this only applies to in-place floordiv //=, because the output type
+ # promotes to float which does not fit
+ a = np.array([1, 2], np.int64)
+ b = np.array([1, 2], np.uint64)
+ pattern = 'could not be coerced to provided output parameter'
+ with assert_raises_regex(TypeError, pattern):
+ a //= b
+
class TestComplexDivision(object):
def test_zero_division(self):
diff --git a/numpy/distutils/misc_util.py b/numpy/distutils/misc_util.py
index 7ba8ad862..d46ff8981 100644
--- a/numpy/distutils/misc_util.py
+++ b/numpy/distutils/misc_util.py
@@ -2329,8 +2329,11 @@ def generate_config_py(target):
extra_dll_dir = os.path.join(os.path.dirname(__file__), '.libs')
if sys.platform == 'win32' and os.path.isdir(extra_dll_dir):
- os.environ.setdefault('PATH', '')
- os.environ['PATH'] += os.pathsep + extra_dll_dir
+ if sys.version_info >= (3, 8):
+ os.add_dll_directory(extra_dll_dir)
+ else:
+ os.environ.setdefault('PATH', '')
+ os.environ['PATH'] += os.pathsep + extra_dll_dir
"""))
diff --git a/numpy/lib/type_check.py b/numpy/lib/type_check.py
index 586824743..8b9e4b8ab 100644
--- a/numpy/lib/type_check.py
+++ b/numpy/lib/type_check.py
@@ -68,16 +68,14 @@ def mintypecode(typechars, typeset='GDFgdf', default='d'):
'G'
"""
- typecodes = [(isinstance(t, str) and t) or asarray(t).dtype.char
- for t in typechars]
- intersection = [t for t in typecodes if t in typeset]
+ typecodes = ((isinstance(t, str) and t) or asarray(t).dtype.char
+ for t in typechars)
+ intersection = set(t for t in typecodes if t in typeset)
if not intersection:
return default
if 'F' in intersection and 'd' in intersection:
return 'D'
- l = [(_typecodes_by_elsize.index(t), t) for t in intersection]
- l.sort()
- return l[0][1]
+ return min((_typecodes_by_elsize.index(t), t) for t in intersection)[1]
def _asfarray_dispatcher(a, dtype=None):
diff --git a/numpy/linalg/linalg.py b/numpy/linalg/linalg.py
index 665b9fbec..f1b2c2228 100644
--- a/numpy/linalg/linalg.py
+++ b/numpy/linalg/linalg.py
@@ -2325,16 +2325,19 @@ def norm(x, ord=None, axis=None, keepdims=False):
Parameters
----------
x : array_like
- Input array. If `axis` is None, `x` must be 1-D or 2-D.
+ Input array. If `axis` is None, `x` must be 1-D or 2-D, unless `ord`
+ is None. If both `axis` and `ord` are None, the 2-norm of
+ ``x.ravel`` will be returned.
ord : {non-zero int, inf, -inf, 'fro', 'nuc'}, optional
Order of the norm (see table under ``Notes``). inf means numpy's
- `inf` object.
- axis : {int, 2-tuple of ints, None}, optional
+ `inf` object. The default is None.
+ axis : {None, int, 2-tuple of ints}, optional.
If `axis` is an integer, it specifies the axis of `x` along which to
compute the vector norms. If `axis` is a 2-tuple, it specifies the
axes that hold 2-D matrices, and the matrix norms of these matrices
are computed. If `axis` is None then either a vector norm (when `x`
- is 1-D) or a matrix norm (when `x` is 2-D) is returned.
+ is 1-D) or a matrix norm (when `x` is 2-D) is returned. The default
+ is None.
.. versionadded:: 1.8.0
diff --git a/numpy/ma/core.py b/numpy/ma/core.py
index bb0d8d412..2baf547a4 100644
--- a/numpy/ma/core.py
+++ b/numpy/ma/core.py
@@ -602,8 +602,10 @@ def filled(a, fill_value=None):
----------
a : MaskedArray or array_like
An input object.
- fill_value : scalar, optional
- Filling value. Default is None.
+ fill_value : array_like, optional.
+ Can be scalar or non-scalar. If non-scalar, the
+ resulting filled array should be broadcastable
+ over input array. Default is None.
Returns
-------
@@ -623,10 +625,19 @@ def filled(a, fill_value=None):
array([[999999, 1, 2],
[999999, 4, 5],
[ 6, 7, 8]])
+ >>> x.filled(fill_value=333)
+ array([[333, 1, 2],
+ [333, 4, 5],
+ [ 6, 7, 8]])
+ >>> x.filled(fill_value=np.arange(3))
+ array([[0, 1, 2],
+ [0, 4, 5],
+ [6, 7, 8]])
"""
if hasattr(a, 'filled'):
return a.filled(fill_value)
+
elif isinstance(a, ndarray):
# Should we check for contiguity ? and a.flags['CONTIGUOUS']:
return a
@@ -3653,6 +3664,14 @@ class MaskedArray(ndarray):
@fill_value.setter
def fill_value(self, value=None):
target = _check_fill_value(value, self.dtype)
+ if not target.ndim == 0:
+ # 2019-11-12, 1.18.0
+ warnings.warn(
+ "Non-scalar arrays for the fill value are deprecated. Use "
+ "arrays with scalar values instead. The filled function "
+ "still supports any array as `fill_value`.",
+ DeprecationWarning, stacklevel=2)
+
_fill_value = self._fill_value
if _fill_value is None:
# Create the attribute if it was undefined
@@ -3673,9 +3692,11 @@ class MaskedArray(ndarray):
Parameters
----------
- fill_value : scalar, optional
- The value to use for invalid entries (None by default).
- If None, the `fill_value` attribute of the array is used instead.
+ fill_value : array_like, optional
+ The value to use for invalid entries. Can be scalar or non-scalar.
+ If non-scalar, the resulting ndarray must be broadcastable over
+ input array. Default is None, in which case, the `fill_value`
+ attribute of the array is used instead.
Returns
-------
@@ -3694,6 +3715,8 @@ class MaskedArray(ndarray):
>>> x = np.ma.array([1,2,3,4,5], mask=[0,0,1,0,1], fill_value=-999)
>>> x.filled()
array([ 1, 2, -999, 4, -999])
+ >>> x.filled(fill_value=1000)
+ array([ 1, 2, 1000, 4, 1000])
>>> type(x.filled())
<class 'numpy.ndarray'>
@@ -6220,9 +6243,11 @@ class mvoid(MaskedArray):
Parameters
----------
- fill_value : scalar, optional
- The value to use for invalid entries (None by default).
- If None, the `fill_value` attribute is used instead.
+ fill_value : array_like, optional
+ The value to use for invalid entries. Can be scalar or
+ non-scalar. If latter is the case, the filled array should
+ be broadcastable over input array. Default is None, in
+ which case the `fill_value` attribute is used instead.
Returns
-------
diff --git a/numpy/random/tests/test_extending.py b/numpy/random/tests/test_extending.py
index 6f0f7a462..efd922ff5 100644
--- a/numpy/random/tests/test_extending.py
+++ b/numpy/random/tests/test_extending.py
@@ -11,6 +11,12 @@ try:
except ImportError:
numba = None
+try:
+ import cython
+except ImportError:
+ cython = None
+
+@pytest.mark.skipif(cython is None, reason="requires cython")
def test_cython():
curdir = os.getcwd()
argv = sys.argv