|
13 | 13 | Timestamp,
|
14 | 14 | )
|
15 | 15 | from pandas.compat import np_version_under1p18
|
| 16 | +import pandas.util._test_decorators as td |
16 | 17 |
|
17 | 18 | import pandas as pd
|
18 | 19 | from pandas import (
|
|
28 | 29 | PeriodArray,
|
29 | 30 | TimedeltaArray,
|
30 | 31 | )
|
| 32 | +from pandas.core.arrays.datetimes import sequence_to_dt64ns |
| 33 | +from pandas.core.arrays.timedeltas import sequence_to_td64ns |
31 | 34 |
|
32 | 35 |
|
33 | 36 | # TODO: more freq variants
|
@@ -224,7 +227,7 @@ def test_unbox_scalar(self):
|
224 | 227 | result = arr._unbox_scalar(NaT)
|
225 | 228 | assert isinstance(result, expected)
|
226 | 229 |
|
227 |
| - msg = f"'value' should be a {self.dtype.__name__}." |
| 230 | + msg = f"'value' should be a {self.scalar_type.__name__}." |
228 | 231 | with pytest.raises(ValueError, match=msg):
|
229 | 232 | arr._unbox_scalar("foo")
|
230 | 233 |
|
@@ -614,11 +617,21 @@ def test_median(self, arr1d):
|
614 | 617 | result = arr2.median(axis=1, skipna=False)
|
615 | 618 | tm.assert_equal(result, arr)
|
616 | 619 |
|
| 620 | + def test_from_integer_array(self): |
| 621 | + arr = np.array([1, 2, 3], dtype=np.int64) |
| 622 | + expected = self.array_cls(arr, dtype=self.example_dtype) |
| 623 | + |
| 624 | + data = pd.array(arr, dtype="Int64") |
| 625 | + result = self.array_cls(data, dtype=self.example_dtype) |
| 626 | + |
| 627 | + tm.assert_extension_array_equal(result, expected) |
| 628 | + |
617 | 629 |
|
618 | 630 | class TestDatetimeArray(SharedTests):
|
619 | 631 | index_cls = DatetimeIndex
|
620 | 632 | array_cls = DatetimeArray
|
621 |
| - dtype = Timestamp |
| 633 | + scalar_type = Timestamp |
| 634 | + example_dtype = "M8[ns]" |
622 | 635 |
|
623 | 636 | @pytest.fixture
|
624 | 637 | def arr1d(self, tz_naive_fixture, freqstr):
|
@@ -918,7 +931,8 @@ def test_strftime_nat(self):
|
918 | 931 | class TestTimedeltaArray(SharedTests):
|
919 | 932 | index_cls = TimedeltaIndex
|
920 | 933 | array_cls = TimedeltaArray
|
921 |
| - dtype = pd.Timedelta |
| 934 | + scalar_type = pd.Timedelta |
| 935 | + example_dtype = "m8[ns]" |
922 | 936 |
|
923 | 937 | def test_from_tdi(self):
|
924 | 938 | tdi = TimedeltaIndex(["1 Day", "3 Hours"])
|
@@ -1037,7 +1051,8 @@ def test_take_fill_valid(self, timedelta_index):
|
1037 | 1051 | class TestPeriodArray(SharedTests):
|
1038 | 1052 | index_cls = PeriodIndex
|
1039 | 1053 | array_cls = PeriodArray
|
1040 |
| - dtype = Period |
| 1054 | + scalar_type = Period |
| 1055 | + example_dtype = PeriodIndex([], freq="W").dtype |
1041 | 1056 |
|
1042 | 1057 | @pytest.fixture
|
1043 | 1058 | def arr1d(self, period_index):
|
@@ -1305,3 +1320,100 @@ def test_period_index_construction_from_strings(klass):
|
1305 | 1320 | result = PeriodIndex(data, freq="Q")
|
1306 | 1321 | expected = PeriodIndex([Period(s) for s in strings])
|
1307 | 1322 | tm.assert_index_equal(result, expected)
|
| 1323 | + |
| 1324 | + |
| 1325 | +@pytest.mark.parametrize("dtype", ["M8[ns]", "m8[ns]"]) |
| 1326 | +def test_from_pandas_array(dtype): |
| 1327 | + # GH#24615 |
| 1328 | + data = np.array([1, 2, 3], dtype=dtype) |
| 1329 | + arr = PandasArray(data) |
| 1330 | + |
| 1331 | + cls = {"M8[ns]": DatetimeArray, "m8[ns]": TimedeltaArray}[dtype] |
| 1332 | + |
| 1333 | + result = cls(arr) |
| 1334 | + expected = cls(data) |
| 1335 | + tm.assert_extension_array_equal(result, expected) |
| 1336 | + |
| 1337 | + result = cls._from_sequence(arr) |
| 1338 | + expected = cls._from_sequence(data) |
| 1339 | + tm.assert_extension_array_equal(result, expected) |
| 1340 | + |
| 1341 | + func = {"M8[ns]": sequence_to_dt64ns, "m8[ns]": sequence_to_td64ns}[dtype] |
| 1342 | + result = func(arr)[0] |
| 1343 | + expected = func(data)[0] |
| 1344 | + tm.assert_equal(result, expected) |
| 1345 | + |
| 1346 | + func = {"M8[ns]": pd.to_datetime, "m8[ns]": pd.to_timedelta}[dtype] |
| 1347 | + result = func(arr).array |
| 1348 | + expected = func(data).array |
| 1349 | + tm.assert_equal(result, expected) |
| 1350 | + |
| 1351 | + # Let's check the Indexes while we're here |
| 1352 | + idx_cls = {"M8[ns]": DatetimeIndex, "m8[ns]": TimedeltaIndex}[dtype] |
| 1353 | + result = idx_cls(arr) |
| 1354 | + expected = idx_cls(data) |
| 1355 | + tm.assert_index_equal(result, expected) |
| 1356 | + |
| 1357 | + |
| 1358 | +@pytest.fixture( |
| 1359 | + params=[ |
| 1360 | + "memoryview", |
| 1361 | + "array", |
| 1362 | + pytest.param("dask", marks=td.skip_if_no("dask.array")), |
| 1363 | + pytest.param("xarray", marks=td.skip_if_no("xarray")), |
| 1364 | + ] |
| 1365 | +) |
| 1366 | +def array_likes(request): |
| 1367 | + # GH#24539 recognize e.g xarray, dask, ... |
| 1368 | + arr = np.array([1, 2, 3], dtype=np.int64) |
| 1369 | + |
| 1370 | + name = request.param |
| 1371 | + if name == "memoryview": |
| 1372 | + data = memoryview(arr) |
| 1373 | + elif name == "array": |
| 1374 | + # stdlib array |
| 1375 | + from array import array |
| 1376 | + |
| 1377 | + data = array("i", arr) |
| 1378 | + elif name == "dask": |
| 1379 | + import dask.array |
| 1380 | + |
| 1381 | + data = dask.array.array(arr) |
| 1382 | + elif name == "xarray": |
| 1383 | + import xarray as xr |
| 1384 | + |
| 1385 | + data = xr.DataArray(arr) |
| 1386 | + |
| 1387 | + return arr, data |
| 1388 | + |
| 1389 | + |
| 1390 | +@pytest.mark.parametrize("dtype", ["M8[ns]", "m8[ns]"]) |
| 1391 | +def test_from_obscure_array(dtype, array_likes): |
| 1392 | + # GH#24539 recognize e.g xarray, dask, ... |
| 1393 | + # Note: we dont do this for PeriodArray bc _from_sequence won't accept |
| 1394 | + # an array of integers |
| 1395 | + # TODO: could check with arraylike of Period objects |
| 1396 | + arr, data = array_likes |
| 1397 | + |
| 1398 | + cls = {"M8[ns]": DatetimeArray, "m8[ns]": TimedeltaArray}[dtype] |
| 1399 | + |
| 1400 | + expected = cls(arr) |
| 1401 | + result = cls._from_sequence(data) |
| 1402 | + tm.assert_extension_array_equal(result, expected) |
| 1403 | + |
| 1404 | + func = {"M8[ns]": sequence_to_dt64ns, "m8[ns]": sequence_to_td64ns}[dtype] |
| 1405 | + result = func(arr)[0] |
| 1406 | + expected = func(data)[0] |
| 1407 | + tm.assert_equal(result, expected) |
| 1408 | + |
| 1409 | + # FIXME: dask and memoryview both break on these |
| 1410 | + # func = {"M8[ns]": pd.to_datetime, "m8[ns]": pd.to_timedelta}[dtype] |
| 1411 | + # result = func(arr).array |
| 1412 | + # expected = func(data).array |
| 1413 | + # tm.assert_equal(result, expected) |
| 1414 | + |
| 1415 | + # Let's check the Indexes while we're here |
| 1416 | + idx_cls = {"M8[ns]": DatetimeIndex, "m8[ns]": TimedeltaIndex}[dtype] |
| 1417 | + result = idx_cls(arr) |
| 1418 | + expected = idx_cls(data) |
| 1419 | + tm.assert_index_equal(result, expected) |
0 commit comments