Skip to content

Commit 9a4b7a2

Browse files
committed
API: Move back to original semantics for np.astype
1 parent dfd46e6 commit 9a4b7a2

File tree

19 files changed

+134
-110
lines changed

19 files changed

+134
-110
lines changed

benchmarks/benchmarks/bench_array_coercion.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@ def time_array_dtype_not_kwargs(self, array_like):
2323
np.array(array_like, self.int64)
2424

2525
def time_array_no_copy(self, array_like):
26-
np.array(array_like, copy=False)
26+
np.array(array_like, copy=None)
2727

2828
def time_array_subok(self, array_like):
2929
np.array(array_like, subok=True)
3030

3131
def time_array_all_kwargs(self, array_like):
32-
np.array(array_like, dtype=self.int64, copy=False, order="F",
32+
np.array(array_like, dtype=self.int64, copy=None, order="F",
3333
subok=False, ndmin=2)
3434

3535
def time_asarray(self, array_like):
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
New ``copy`` keyword meaning for `numpy.array` and `numpy.asarray`
2+
------------------------------------------------------------------
3+
Now `numpy.array` and `numpy.asarray` support three values for ``copy`` parameter:
4+
* ``None`` - A copy will only be made if it is necessary.
5+
* ``True`` - Always make a copy.
6+
* ``False`` - Never make a copy. If a copy is required a ``ValueError`` is raised.
7+
8+
The meaning of ``False`` changed as it now raises an exception if a copy is needed.

numpy/_core/_add_newdocs.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@
807807
a default ``dtype`` that can represent the values (by applying promotion
808808
rules when necessary.)
809809
copy : bool, optional
810-
If ``True`` (default), then the object is copied. If ``False``, a copy
810+
If ``True`` (default), then the object is copied. If ``None``, a copy
811811
will only be made if ``__array__`` returns a copy, if obj is a nested
812812
sequence, or if a copy is needed to satisfy any of the other
813813
requirements (``dtype``, ``order``, etc.). For ``False`` it raises

numpy/_core/function_base.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -181,9 +181,9 @@ def linspace(start, stop, num=50, endpoint=True, retstep=False, dtype=None,
181181
_nx.floor(y, out=y)
182182

183183
if retstep:
184-
return y.astype(dtype, copy=None), step
184+
return y.astype(dtype, copy=False), step
185185
else:
186-
return y.astype(dtype, copy=None)
186+
return y.astype(dtype, copy=False)
187187

188188

189189
def _logspace_dispatcher(start, stop, num=None, endpoint=None, base=None,
@@ -300,7 +300,7 @@ def logspace(start, stop, num=50, endpoint=True, base=10.0, dtype=None,
300300
base = np.expand_dims(base, axis=axis)
301301
if dtype is None:
302302
return _nx.power(base, y)
303-
return _nx.power(base, y).astype(dtype, copy=None)
303+
return _nx.power(base, y).astype(dtype, copy=False)
304304

305305

306306
def _geomspace_dispatcher(start, stop, num=None, endpoint=None, dtype=None,
@@ -463,7 +463,7 @@ def geomspace(start, stop, num=50, endpoint=True, dtype=None, axis=0):
463463
if axis != 0:
464464
result = _nx.moveaxis(result, 0, axis)
465465

466-
return result.astype(dtype, copy=None)
466+
return result.astype(dtype, copy=False)
467467

468468

469469
def _needs_add_docstring(obj):

numpy/_core/numeric.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -478,7 +478,7 @@ def count_nonzero(a, axis=None, *, keepdims=False):
478478
if np.issubdtype(a.dtype, np.character):
479479
a_bool = a != a.dtype.type()
480480
else:
481-
a_bool = a.astype(np.bool, copy=None)
481+
a_bool = a.astype(np.bool, copy=False)
482482

483483
return a_bool.sum(axis=axis, dtype=np.intp, keepdims=keepdims)
484484

numpy/_core/src/multiarray/conversion_utils.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,31 @@ PyArray_CopyConverter(PyObject *obj, NPY_COPYMODE *copymode) {
260260
return NPY_SUCCEED;
261261
}
262262

263+
NPY_NO_EXPORT int
264+
PyArray_AsTypeCopyConverter(PyObject *obj, NPY_ASTYPECOPYMODE *copymode)
265+
{
266+
int int_copymode;
267+
static PyObject* numpy_CopyMode = NULL;
268+
npy_cache_import("numpy", "_CopyMode", &numpy_CopyMode);
269+
270+
if (numpy_CopyMode != NULL && (PyObject *)Py_TYPE(obj) == numpy_CopyMode) {
271+
PyErr_SetString(PyExc_ValueError,
272+
"_CopyMode enum is not allowed for astype function. "
273+
"Use true/false instead.");
274+
return NPY_FAIL;
275+
}
276+
else {
277+
npy_bool bool_copymode;
278+
if (!PyArray_BoolConverter(obj, &bool_copymode)) {
279+
return NPY_FAIL;
280+
}
281+
int_copymode = (int)bool_copymode;
282+
}
283+
284+
*copymode = (NPY_ASTYPECOPYMODE)int_copymode;
285+
return NPY_SUCCEED;
286+
}
287+
263288
/*NUMPY_API
264289
* Get buffer chunk from object
265290
*

numpy/_core/src/multiarray/conversion_utils.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,17 @@ typedef enum {
1818
NPY_COPY_IF_NEEDED = 2,
1919
} NPY_COPYMODE;
2020

21+
typedef enum {
22+
NPY_AS_TYPE_COPY_IF_NEEDED = 0,
23+
NPY_AS_TYPE_COPY_ALWAYS = 1,
24+
} NPY_ASTYPECOPYMODE;
25+
2126
NPY_NO_EXPORT int
2227
PyArray_CopyConverter(PyObject *obj, NPY_COPYMODE *copyflag);
2328

29+
NPY_NO_EXPORT int
30+
PyArray_AsTypeCopyConverter(PyObject *obj, NPY_ASTYPECOPYMODE *copyflag);
31+
2432
NPY_NO_EXPORT int
2533
PyArray_BufferConverter(PyObject *obj, PyArray_Chunk *buf);
2634

numpy/_core/src/multiarray/methods.c

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -782,7 +782,7 @@ array_astype(PyArrayObject *self,
782782
npy_dtype_info dt_info = {NULL, NULL};
783783
NPY_CASTING casting = NPY_UNSAFE_CASTING;
784784
NPY_ORDER order = NPY_KEEPORDER;
785-
NPY_COPYMODE forcecopy = 1;
785+
NPY_ASTYPECOPYMODE forcecopy = 1;
786786
int subok = 1;
787787

788788
NPY_PREPARE_ARGPARSER;
@@ -791,7 +791,7 @@ array_astype(PyArrayObject *self,
791791
"|order", &PyArray_OrderConverter, &order,
792792
"|casting", &PyArray_CastingConverter, &casting,
793793
"|subok", &PyArray_PythonPyIntFromInt, &subok,
794-
"|copy", &PyArray_CopyConverter, &forcecopy,
794+
"|copy", &PyArray_AsTypeCopyConverter, &forcecopy,
795795
NULL, NULL, NULL) < 0) {
796796
Py_XDECREF(dt_info.descr);
797797
Py_XDECREF(dt_info.dtype);
@@ -813,7 +813,7 @@ array_astype(PyArrayObject *self,
813813
* and it's not a subtype if subok is False, then we
814814
* can skip the copy.
815815
*/
816-
if (forcecopy != NPY_COPY_ALWAYS &&
816+
if (forcecopy != NPY_AS_TYPE_COPY_ALWAYS &&
817817
(order == NPY_KEEPORDER ||
818818
(order == NPY_ANYORDER &&
819819
(PyArray_IS_C_CONTIGUOUS(self) ||
@@ -829,14 +829,6 @@ array_astype(PyArrayObject *self,
829829
return (PyObject *)self;
830830
}
831831

832-
if (forcecopy == NPY_COPY_NEVER) {
833-
PyErr_SetString(PyExc_ValueError,
834-
"Unable to avoid copy while casting in never copy mode. "
835-
"Use copy=None to copy only if necessary.");
836-
Py_DECREF(dtype);
837-
return NULL;
838-
}
839-
840832
if (!PyArray_CanCastArrayTo(self, dtype, casting)) {
841833
PyErr_Clear();
842834
npy_set_invalid_cast_error(

numpy/_core/tests/test_api.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -183,12 +183,12 @@ def test_array_astype():
183183

184184
# order parameter allows overriding of the memory layout,
185185
# forcing a copy if the layout is wrong
186-
b = a.astype('f4', order='F', copy=None)
186+
b = a.astype('f4', order='F', copy=False)
187187
assert_equal(a, b)
188188
assert_(not (a is b))
189189
assert_(b.flags.f_contiguous)
190190

191-
b = a.astype('f4', order='C', copy=None)
191+
b = a.astype('f4', order='C', copy=False)
192192
assert_equal(a, b)
193193
assert_(a is b)
194194
assert_(b.flags.c_contiguous)
@@ -214,12 +214,12 @@ class MyNDArray(np.ndarray):
214214
assert_(a is b)
215215

216216
# subok=True is default, and creates a subtype on a cast
217-
b = a.astype('i4', copy=None)
217+
b = a.astype('i4', copy=False)
218218
assert_equal(a, b)
219219
assert_equal(type(b), MyNDArray)
220220

221221
# subok=False never returns a subclass
222-
b = a.astype('f4', subok=False, copy=None)
222+
b = a.astype('f4', subok=False, copy=False)
223223
assert_equal(a, b)
224224
assert_(not (a is b))
225225
assert_(type(b) is not MyNDArray)
@@ -570,22 +570,14 @@ def test_astype_copyflag():
570570
arr = np.arange(10, dtype=np.intp)
571571

572572
res_true = arr.astype(np.intp, copy=True)
573-
assert not np.may_share_memory(arr, res_true)
574-
res_always = arr.astype(np.intp, copy=np._CopyMode.ALWAYS)
575-
assert not np.may_share_memory(arr, res_always)
573+
assert not np.shares_memory(arr, res_true)
576574

577575
res_false = arr.astype(np.intp, copy=False)
578-
# `res_false is arr` currently, but check `may_share_memory`.
579-
assert np.may_share_memory(arr, res_false)
580-
res_if_needed = arr.astype(np.intp, copy=None)
581-
# `res_if_needed is arr` currently, but check `may_share_memory`.
582-
assert np.may_share_memory(arr, res_if_needed)
583-
584-
res_never = arr.astype(np.intp, copy=np._CopyMode.NEVER)
585-
assert np.may_share_memory(arr, res_never)
586-
587-
# Simple tests for when a copy is necessary:
588-
res_if_needed = arr.astype(np.float64, copy=None)
589-
assert_array_equal(res_if_needed, arr)
576+
assert np.shares_memory(arr, res_false)
577+
578+
res_false_float = arr.astype(np.float64, copy=False)
579+
assert not np.shares_memory(arr, res_false_float)
580+
581+
# _CopyMode enum isn't allowed
590582
assert_raises(ValueError, arr.astype, np.float64,
591-
copy=False)
583+
copy=np._CopyMode.NEVER)

numpy/fft/tests/test_pocketfft.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,7 @@ def test_fft_with_order(dtype, order, fft):
241241
# Check that FFT/IFFT produces identical results for C, Fortran and
242242
# non contiguous arrays
243243
rng = np.random.RandomState(42)
244-
X = rng.rand(8, 7, 13).astype(dtype, copy=None)
244+
X = rng.rand(8, 7, 13).astype(dtype, copy=False)
245245
# See discussion in pull/14178
246246
_tol = 8.0 * np.sqrt(np.log2(X.size)) * np.finfo(X.dtype).eps
247247
if order == 'F':

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy