diff options
| author | Sebastian Berg <sebastian@sipsolutions.net> | 2020-09-28 18:12:14 -0500 |
|---|---|---|
| committer | Sebastian Berg <sebastian@sipsolutions.net> | 2020-09-28 18:51:18 -0500 |
| commit | 127b262b0da014e624889532c3d4eb330ed2aa07 (patch) | |
| tree | 8dd4519ed8e201e5552f97685f5fd048a8b9d2f1 /numpy | |
| parent | a1454867ab910a356588c511700c99ec6bef93b5 (diff) | |
| download | numpy-127b262b0da014e624889532c3d4eb330ed2aa07.tar.gz | |
BUG: Fix default void, datetime, and timedelta in array coercion
When converting an empty sequence to an array, datetimes would
use an incorrect itemsize (on master only).
The legacy behaviour of void is that it uses 8 bytes, which is
due to the fact that `[]` uses `float64` by default which has
8 bytes.
Diffstat (limited to 'numpy')
| -rw-r--r-- | numpy/core/src/multiarray/dtypemeta.c | 31 | ||||
| -rw-r--r-- | numpy/core/tests/test_array_coercion.py | 16 |
2 files changed, 44 insertions, 3 deletions
diff --git a/numpy/core/src/multiarray/dtypemeta.c b/numpy/core/src/multiarray/dtypemeta.c index 531f746d8..dbe5ba476 100644 --- a/numpy/core/src/multiarray/dtypemeta.c +++ b/numpy/core/src/multiarray/dtypemeta.c @@ -204,8 +204,32 @@ nonparametric_default_descr(PyArray_DTypeMeta *cls) } +/* Ensure a copy of the singleton (just in case we do adapt it somewhere) */ static PyArray_Descr * -flexible_default_descr(PyArray_DTypeMeta *cls) +datetime_and_timedelta_default_descr(PyArray_DTypeMeta *cls) +{ + return PyArray_DescrNew(cls->singleton); +} + + +static PyArray_Descr * +void_default_descr(PyArray_DTypeMeta *cls) +{ + PyArray_Descr *res = PyArray_DescrNew(cls->singleton); + if (res == NULL) { + return NULL; + } + /* + * The legacy behaviour for `np.array([], dtype="V")` is to use "V8". + * This is because `[]` uses `float64` as dtype, and then that is used + * for the size of the requested void. + */ + res->elsize = 8; + return res; +} + +static PyArray_Descr * +string_and_unicode_default_descr(PyArray_DTypeMeta *cls) { PyArray_Descr *res = PyArray_DescrNewFromType(cls->type_num); if (res == NULL) { @@ -534,7 +558,7 @@ dtypemeta_wrap_legacy_descriptor(PyArray_Descr *descr) else if (PyTypeNum_ISDATETIME(descr->type_num)) { /* Datetimes are flexible, but were not considered previously */ dtype_class->parametric = NPY_TRUE; - dtype_class->default_descr = flexible_default_descr; + dtype_class->default_descr = datetime_and_timedelta_default_descr; dtype_class->discover_descr_from_pyobject = ( discover_datetime_and_timedelta_from_pyobject); dtype_class->common_dtype = datetime_common_dtype; @@ -545,13 +569,14 @@ dtypemeta_wrap_legacy_descriptor(PyArray_Descr *descr) } else if (PyTypeNum_ISFLEXIBLE(descr->type_num)) { dtype_class->parametric = NPY_TRUE; - dtype_class->default_descr = flexible_default_descr; if (descr->type_num == NPY_VOID) { + dtype_class->default_descr = void_default_descr; dtype_class->discover_descr_from_pyobject = ( void_discover_descr_from_pyobject); dtype_class->common_instance = void_common_instance; } else { + dtype_class->default_descr = string_and_unicode_default_descr; dtype_class->is_known_scalar_type = string_known_scalar_types; dtype_class->discover_descr_from_pyobject = ( string_discover_descr_from_pyobject); diff --git a/numpy/core/tests/test_array_coercion.py b/numpy/core/tests/test_array_coercion.py index a6c8cc8b2..e0480c7bf 100644 --- a/numpy/core/tests/test_array_coercion.py +++ b/numpy/core/tests/test_array_coercion.py @@ -324,6 +324,22 @@ class TestScalarDiscovery: ass[()] = scalar assert_array_equal(ass, cast) + @pytest.mark.parametrize("dtype_char", np.typecodes["All"]) + def test_default_dtype_instance(self, dtype_char): + if dtype_char in "SU": + dtype = np.dtype(dtype_char + "1") + elif dtype_char == "V": + # Legacy behaviour was to use V8. The reason was float64 being the + # default dtype and that having 8 bytes. + dtype = np.dtype("V8") + else: + dtype = np.dtype(dtype_char) + + discovered_dtype, _ = _discover_array_parameters([], type(dtype)) + + assert discovered_dtype == dtype + assert discovered_dtype.itemsize == dtype.itemsize + class TestTimeScalars: @pytest.mark.parametrize("dtype", [np.int64, np.float32]) |
