test_datetimelike.py 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657
  1. # -*- coding: utf-8 -*-
  2. import numpy as np
  3. import pytest
  4. import pandas.compat as compat
  5. import pandas as pd
  6. from pandas.core.arrays import DatetimeArray, PeriodArray, TimedeltaArray
  7. import pandas.util.testing as tm
  8. # TODO: more freq variants
  9. @pytest.fixture(params=['D', 'B', 'W', 'M', 'Q', 'Y'])
  10. def period_index(request):
  11. """
  12. A fixture to provide PeriodIndex objects with different frequencies.
  13. Most PeriodArray behavior is already tested in PeriodIndex tests,
  14. so here we just test that the PeriodArray behavior matches
  15. the PeriodIndex behavior.
  16. """
  17. freqstr = request.param
  18. # TODO: non-monotone indexes; NaTs, different start dates
  19. pi = pd.period_range(start=pd.Timestamp('2000-01-01'),
  20. periods=100,
  21. freq=freqstr)
  22. return pi
  23. @pytest.fixture(params=['D', 'B', 'W', 'M', 'Q', 'Y'])
  24. def datetime_index(request):
  25. """
  26. A fixture to provide DatetimeIndex objects with different frequencies.
  27. Most DatetimeArray behavior is already tested in DatetimeIndex tests,
  28. so here we just test that the DatetimeArray behavior matches
  29. the DatetimeIndex behavior.
  30. """
  31. freqstr = request.param
  32. # TODO: non-monotone indexes; NaTs, different start dates, timezones
  33. pi = pd.date_range(start=pd.Timestamp('2000-01-01'),
  34. periods=100,
  35. freq=freqstr)
  36. return pi
  37. @pytest.fixture
  38. def timedelta_index(request):
  39. """
  40. A fixture to provide TimedeltaIndex objects with different frequencies.
  41. Most TimedeltaArray behavior is already tested in TimedeltaIndex tests,
  42. so here we just test that the TimedeltaArray behavior matches
  43. the TimedeltaIndex behavior.
  44. """
  45. # TODO: flesh this out
  46. return pd.TimedeltaIndex(['1 Day', '3 Hours', 'NaT'])
  47. class SharedTests(object):
  48. index_cls = None
  49. def test_compare_len1_raises(self):
  50. # make sure we raise when comparing with different lengths, specific
  51. # to the case where one has length-1, which numpy would broadcast
  52. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  53. idx = self.index_cls._simple_new(data, freq='D')
  54. arr = self.array_cls(idx)
  55. with pytest.raises(ValueError, match="Lengths must match"):
  56. arr == arr[:1]
  57. # test the index classes while we're at it, GH#23078
  58. with pytest.raises(ValueError, match="Lengths must match"):
  59. idx <= idx[[0]]
  60. def test_take(self):
  61. data = np.arange(100, dtype='i8') * 24 * 3600 * 10**9
  62. np.random.shuffle(data)
  63. idx = self.index_cls._simple_new(data, freq='D')
  64. arr = self.array_cls(idx)
  65. takers = [1, 4, 94]
  66. result = arr.take(takers)
  67. expected = idx.take(takers)
  68. tm.assert_index_equal(self.index_cls(result), expected)
  69. takers = np.array([1, 4, 94])
  70. result = arr.take(takers)
  71. expected = idx.take(takers)
  72. tm.assert_index_equal(self.index_cls(result), expected)
  73. def test_take_fill(self):
  74. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  75. idx = self.index_cls._simple_new(data, freq='D')
  76. arr = self.array_cls(idx)
  77. result = arr.take([-1, 1], allow_fill=True, fill_value=None)
  78. assert result[0] is pd.NaT
  79. result = arr.take([-1, 1], allow_fill=True, fill_value=np.nan)
  80. assert result[0] is pd.NaT
  81. result = arr.take([-1, 1], allow_fill=True, fill_value=pd.NaT)
  82. assert result[0] is pd.NaT
  83. with pytest.raises(ValueError):
  84. arr.take([0, 1], allow_fill=True, fill_value=2)
  85. with pytest.raises(ValueError):
  86. arr.take([0, 1], allow_fill=True, fill_value=2.0)
  87. with pytest.raises(ValueError):
  88. arr.take([0, 1], allow_fill=True,
  89. fill_value=pd.Timestamp.now().time)
  90. def test_concat_same_type(self):
  91. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  92. idx = self.index_cls._simple_new(data, freq='D').insert(0, pd.NaT)
  93. arr = self.array_cls(idx)
  94. result = arr._concat_same_type([arr[:-1], arr[1:], arr])
  95. expected = idx._concat_same_dtype([idx[:-1], idx[1:], idx], None)
  96. tm.assert_index_equal(self.index_cls(result), expected)
  97. def test_unbox_scalar(self):
  98. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  99. arr = self.array_cls(data, freq='D')
  100. result = arr._unbox_scalar(arr[0])
  101. assert isinstance(result, (int, compat.long))
  102. result = arr._unbox_scalar(pd.NaT)
  103. assert isinstance(result, (int, compat.long))
  104. with pytest.raises(ValueError):
  105. arr._unbox_scalar('foo')
  106. def test_check_compatible_with(self):
  107. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  108. arr = self.array_cls(data, freq='D')
  109. arr._check_compatible_with(arr[0])
  110. arr._check_compatible_with(arr[:1])
  111. arr._check_compatible_with(pd.NaT)
  112. def test_scalar_from_string(self):
  113. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  114. arr = self.array_cls(data, freq='D')
  115. result = arr._scalar_from_string(str(arr[0]))
  116. assert result == arr[0]
  117. def test_reduce_invalid(self):
  118. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  119. arr = self.array_cls(data, freq='D')
  120. with pytest.raises(TypeError, match='cannot perform'):
  121. arr._reduce("not a method")
  122. @pytest.mark.parametrize('method', ['pad', 'backfill'])
  123. def test_fillna_method_doesnt_change_orig(self, method):
  124. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  125. arr = self.array_cls(data, freq='D')
  126. arr[4] = pd.NaT
  127. fill_value = arr[3] if method == 'pad' else arr[5]
  128. result = arr.fillna(method=method)
  129. assert result[4] == fill_value
  130. # check that the original was not changed
  131. assert arr[4] is pd.NaT
  132. def test_searchsorted(self):
  133. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  134. arr = self.array_cls(data, freq='D')
  135. # scalar
  136. result = arr.searchsorted(arr[1])
  137. assert result == 1
  138. result = arr.searchsorted(arr[2], side="right")
  139. assert result == 3
  140. # own-type
  141. result = arr.searchsorted(arr[1:3])
  142. expected = np.array([1, 2], dtype=np.intp)
  143. tm.assert_numpy_array_equal(result, expected)
  144. result = arr.searchsorted(arr[1:3], side="right")
  145. expected = np.array([2, 3], dtype=np.intp)
  146. tm.assert_numpy_array_equal(result, expected)
  147. # Following numpy convention, NaT goes at the beginning
  148. # (unlike NaN which goes at the end)
  149. result = arr.searchsorted(pd.NaT)
  150. assert result == 0
  151. def test_setitem(self):
  152. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  153. arr = self.array_cls(data, freq='D')
  154. arr[0] = arr[1]
  155. expected = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  156. expected[0] = expected[1]
  157. tm.assert_numpy_array_equal(arr.asi8, expected)
  158. arr[:2] = arr[-2:]
  159. expected[:2] = expected[-2:]
  160. tm.assert_numpy_array_equal(arr.asi8, expected)
  161. def test_setitem_raises(self):
  162. data = np.arange(10, dtype='i8') * 24 * 3600 * 10**9
  163. arr = self.array_cls(data, freq='D')
  164. val = arr[0]
  165. with pytest.raises(IndexError, match="index 12 is out of bounds"):
  166. arr[12] = val
  167. with pytest.raises(TypeError, match="'value' should be a.* 'object'"):
  168. arr[0] = object()
  169. class TestDatetimeArray(SharedTests):
  170. index_cls = pd.DatetimeIndex
  171. array_cls = DatetimeArray
  172. def test_round(self, tz_naive_fixture):
  173. # GH#24064
  174. tz = tz_naive_fixture
  175. dti = pd.date_range('2016-01-01 01:01:00', periods=3, freq='H', tz=tz)
  176. result = dti.round(freq='2T')
  177. expected = dti - pd.Timedelta(minutes=1)
  178. tm.assert_index_equal(result, expected)
  179. def test_array_interface(self, datetime_index):
  180. arr = DatetimeArray(datetime_index)
  181. # default asarray gives the same underlying data (for tz naive)
  182. result = np.asarray(arr)
  183. expected = arr._data
  184. assert result is expected
  185. tm.assert_numpy_array_equal(result, expected)
  186. result = np.array(arr, copy=False)
  187. assert result is expected
  188. tm.assert_numpy_array_equal(result, expected)
  189. # specifying M8[ns] gives the same result as default
  190. result = np.asarray(arr, dtype='datetime64[ns]')
  191. expected = arr._data
  192. assert result is expected
  193. tm.assert_numpy_array_equal(result, expected)
  194. result = np.array(arr, dtype='datetime64[ns]', copy=False)
  195. assert result is expected
  196. tm.assert_numpy_array_equal(result, expected)
  197. result = np.array(arr, dtype='datetime64[ns]')
  198. assert result is not expected
  199. tm.assert_numpy_array_equal(result, expected)
  200. # to object dtype
  201. result = np.asarray(arr, dtype=object)
  202. expected = np.array(list(arr), dtype=object)
  203. tm.assert_numpy_array_equal(result, expected)
  204. # to other dtype always copies
  205. result = np.asarray(arr, dtype='int64')
  206. assert result is not arr.asi8
  207. assert not np.may_share_memory(arr, result)
  208. expected = arr.asi8.copy()
  209. tm.assert_numpy_array_equal(result, expected)
  210. # other dtypes handled by numpy
  211. for dtype in ['float64', str]:
  212. result = np.asarray(arr, dtype=dtype)
  213. expected = np.asarray(arr).astype(dtype)
  214. tm.assert_numpy_array_equal(result, expected)
  215. def test_array_object_dtype(self, tz_naive_fixture):
  216. # GH#23524
  217. tz = tz_naive_fixture
  218. dti = pd.date_range('2016-01-01', periods=3, tz=tz)
  219. arr = DatetimeArray(dti)
  220. expected = np.array(list(dti))
  221. result = np.array(arr, dtype=object)
  222. tm.assert_numpy_array_equal(result, expected)
  223. # also test the DatetimeIndex method while we're at it
  224. result = np.array(dti, dtype=object)
  225. tm.assert_numpy_array_equal(result, expected)
  226. def test_array_tz(self, tz_naive_fixture):
  227. # GH#23524
  228. tz = tz_naive_fixture
  229. dti = pd.date_range('2016-01-01', periods=3, tz=tz)
  230. arr = DatetimeArray(dti)
  231. expected = dti.asi8.view('M8[ns]')
  232. result = np.array(arr, dtype='M8[ns]')
  233. tm.assert_numpy_array_equal(result, expected)
  234. result = np.array(arr, dtype='datetime64[ns]')
  235. tm.assert_numpy_array_equal(result, expected)
  236. # check that we are not making copies when setting copy=False
  237. result = np.array(arr, dtype='M8[ns]', copy=False)
  238. assert result.base is expected.base
  239. assert result.base is not None
  240. result = np.array(arr, dtype='datetime64[ns]', copy=False)
  241. assert result.base is expected.base
  242. assert result.base is not None
  243. def test_array_i8_dtype(self, tz_naive_fixture):
  244. tz = tz_naive_fixture
  245. dti = pd.date_range('2016-01-01', periods=3, tz=tz)
  246. arr = DatetimeArray(dti)
  247. expected = dti.asi8
  248. result = np.array(arr, dtype='i8')
  249. tm.assert_numpy_array_equal(result, expected)
  250. result = np.array(arr, dtype=np.int64)
  251. tm.assert_numpy_array_equal(result, expected)
  252. # check that we are still making copies when setting copy=False
  253. result = np.array(arr, dtype='i8', copy=False)
  254. assert result.base is not expected.base
  255. assert result.base is None
  256. def test_from_array_keeps_base(self):
  257. # Ensure that DatetimeArray._data.base isn't lost.
  258. arr = np.array(['2000-01-01', '2000-01-02'], dtype='M8[ns]')
  259. dta = DatetimeArray(arr)
  260. assert dta._data is arr
  261. dta = DatetimeArray(arr[:0])
  262. assert dta._data.base is arr
  263. def test_from_dti(self, tz_naive_fixture):
  264. tz = tz_naive_fixture
  265. dti = pd.date_range('2016-01-01', periods=3, tz=tz)
  266. arr = DatetimeArray(dti)
  267. assert list(dti) == list(arr)
  268. # Check that Index.__new__ knows what to do with DatetimeArray
  269. dti2 = pd.Index(arr)
  270. assert isinstance(dti2, pd.DatetimeIndex)
  271. assert list(dti2) == list(arr)
  272. def test_astype_object(self, tz_naive_fixture):
  273. tz = tz_naive_fixture
  274. dti = pd.date_range('2016-01-01', periods=3, tz=tz)
  275. arr = DatetimeArray(dti)
  276. asobj = arr.astype('O')
  277. assert isinstance(asobj, np.ndarray)
  278. assert asobj.dtype == 'O'
  279. assert list(asobj) == list(dti)
  280. @pytest.mark.parametrize('freqstr', ['D', 'B', 'W', 'M', 'Q', 'Y'])
  281. def test_to_perioddelta(self, datetime_index, freqstr):
  282. # GH#23113
  283. dti = datetime_index
  284. arr = DatetimeArray(dti)
  285. expected = dti.to_perioddelta(freq=freqstr)
  286. result = arr.to_perioddelta(freq=freqstr)
  287. assert isinstance(result, TimedeltaArray)
  288. # placeholder until these become actual EA subclasses and we can use
  289. # an EA-specific tm.assert_ function
  290. tm.assert_index_equal(pd.Index(result), pd.Index(expected))
  291. @pytest.mark.parametrize('freqstr', ['D', 'B', 'W', 'M', 'Q', 'Y'])
  292. def test_to_period(self, datetime_index, freqstr):
  293. dti = datetime_index
  294. arr = DatetimeArray(dti)
  295. expected = dti.to_period(freq=freqstr)
  296. result = arr.to_period(freq=freqstr)
  297. assert isinstance(result, PeriodArray)
  298. # placeholder until these become actual EA subclasses and we can use
  299. # an EA-specific tm.assert_ function
  300. tm.assert_index_equal(pd.Index(result), pd.Index(expected))
  301. @pytest.mark.parametrize('propname', pd.DatetimeIndex._bool_ops)
  302. def test_bool_properties(self, datetime_index, propname):
  303. # in this case _bool_ops is just `is_leap_year`
  304. dti = datetime_index
  305. arr = DatetimeArray(dti)
  306. assert dti.freq == arr.freq
  307. result = getattr(arr, propname)
  308. expected = np.array(getattr(dti, propname), dtype=result.dtype)
  309. tm.assert_numpy_array_equal(result, expected)
  310. @pytest.mark.parametrize('propname', pd.DatetimeIndex._field_ops)
  311. def test_int_properties(self, datetime_index, propname):
  312. dti = datetime_index
  313. arr = DatetimeArray(dti)
  314. result = getattr(arr, propname)
  315. expected = np.array(getattr(dti, propname), dtype=result.dtype)
  316. tm.assert_numpy_array_equal(result, expected)
  317. def test_take_fill_valid(self, datetime_index, tz_naive_fixture):
  318. dti = datetime_index.tz_localize(tz_naive_fixture)
  319. arr = DatetimeArray(dti)
  320. now = pd.Timestamp.now().tz_localize(dti.tz)
  321. result = arr.take([-1, 1], allow_fill=True, fill_value=now)
  322. assert result[0] == now
  323. with pytest.raises(ValueError):
  324. # fill_value Timedelta invalid
  325. arr.take([-1, 1], allow_fill=True, fill_value=now - now)
  326. with pytest.raises(ValueError):
  327. # fill_value Period invalid
  328. arr.take([-1, 1], allow_fill=True, fill_value=pd.Period('2014Q1'))
  329. tz = None if dti.tz is not None else 'US/Eastern'
  330. now = pd.Timestamp.now().tz_localize(tz)
  331. with pytest.raises(TypeError):
  332. # Timestamp with mismatched tz-awareness
  333. arr.take([-1, 1], allow_fill=True, fill_value=now)
  334. with pytest.raises(ValueError):
  335. # require NaT, not iNaT, as it could be confused with an integer
  336. arr.take([-1, 1], allow_fill=True, fill_value=pd.NaT.value)
  337. def test_concat_same_type_invalid(self, datetime_index):
  338. # different timezones
  339. dti = datetime_index
  340. arr = DatetimeArray(dti)
  341. if arr.tz is None:
  342. other = arr.tz_localize('UTC')
  343. else:
  344. other = arr.tz_localize(None)
  345. with pytest.raises(AssertionError):
  346. arr._concat_same_type([arr, other])
  347. def test_concat_same_type_different_freq(self):
  348. # we *can* concatentate DTI with different freqs.
  349. a = DatetimeArray(pd.date_range('2000', periods=2, freq='D',
  350. tz='US/Central'))
  351. b = DatetimeArray(pd.date_range('2000', periods=2, freq='H',
  352. tz='US/Central'))
  353. result = DatetimeArray._concat_same_type([a, b])
  354. expected = DatetimeArray(pd.to_datetime([
  355. '2000-01-01 00:00:00', '2000-01-02 00:00:00',
  356. '2000-01-01 00:00:00', '2000-01-01 01:00:00',
  357. ]).tz_localize("US/Central"))
  358. tm.assert_datetime_array_equal(result, expected)
  359. class TestTimedeltaArray(SharedTests):
  360. index_cls = pd.TimedeltaIndex
  361. array_cls = TimedeltaArray
  362. def test_from_tdi(self):
  363. tdi = pd.TimedeltaIndex(['1 Day', '3 Hours'])
  364. arr = TimedeltaArray(tdi)
  365. assert list(arr) == list(tdi)
  366. # Check that Index.__new__ knows what to do with TimedeltaArray
  367. tdi2 = pd.Index(arr)
  368. assert isinstance(tdi2, pd.TimedeltaIndex)
  369. assert list(tdi2) == list(arr)
  370. def test_astype_object(self):
  371. tdi = pd.TimedeltaIndex(['1 Day', '3 Hours'])
  372. arr = TimedeltaArray(tdi)
  373. asobj = arr.astype('O')
  374. assert isinstance(asobj, np.ndarray)
  375. assert asobj.dtype == 'O'
  376. assert list(asobj) == list(tdi)
  377. def test_to_pytimedelta(self, timedelta_index):
  378. tdi = timedelta_index
  379. arr = TimedeltaArray(tdi)
  380. expected = tdi.to_pytimedelta()
  381. result = arr.to_pytimedelta()
  382. tm.assert_numpy_array_equal(result, expected)
  383. def test_total_seconds(self, timedelta_index):
  384. tdi = timedelta_index
  385. arr = TimedeltaArray(tdi)
  386. expected = tdi.total_seconds()
  387. result = arr.total_seconds()
  388. tm.assert_numpy_array_equal(result, expected.values)
  389. @pytest.mark.parametrize('propname', pd.TimedeltaIndex._field_ops)
  390. def test_int_properties(self, timedelta_index, propname):
  391. tdi = timedelta_index
  392. arr = TimedeltaArray(tdi)
  393. result = getattr(arr, propname)
  394. expected = np.array(getattr(tdi, propname), dtype=result.dtype)
  395. tm.assert_numpy_array_equal(result, expected)
  396. def test_array_interface(self, timedelta_index):
  397. arr = TimedeltaArray(timedelta_index)
  398. # default asarray gives the same underlying data
  399. result = np.asarray(arr)
  400. expected = arr._data
  401. assert result is expected
  402. tm.assert_numpy_array_equal(result, expected)
  403. result = np.array(arr, copy=False)
  404. assert result is expected
  405. tm.assert_numpy_array_equal(result, expected)
  406. # specifying m8[ns] gives the same result as default
  407. result = np.asarray(arr, dtype='timedelta64[ns]')
  408. expected = arr._data
  409. assert result is expected
  410. tm.assert_numpy_array_equal(result, expected)
  411. result = np.array(arr, dtype='timedelta64[ns]', copy=False)
  412. assert result is expected
  413. tm.assert_numpy_array_equal(result, expected)
  414. result = np.array(arr, dtype='timedelta64[ns]')
  415. assert result is not expected
  416. tm.assert_numpy_array_equal(result, expected)
  417. # to object dtype
  418. result = np.asarray(arr, dtype=object)
  419. expected = np.array(list(arr), dtype=object)
  420. tm.assert_numpy_array_equal(result, expected)
  421. # to other dtype always copies
  422. result = np.asarray(arr, dtype='int64')
  423. assert result is not arr.asi8
  424. assert not np.may_share_memory(arr, result)
  425. expected = arr.asi8.copy()
  426. tm.assert_numpy_array_equal(result, expected)
  427. # other dtypes handled by numpy
  428. for dtype in ['float64', str]:
  429. result = np.asarray(arr, dtype=dtype)
  430. expected = np.asarray(arr).astype(dtype)
  431. tm.assert_numpy_array_equal(result, expected)
  432. def test_take_fill_valid(self, timedelta_index):
  433. tdi = timedelta_index
  434. arr = TimedeltaArray(tdi)
  435. td1 = pd.Timedelta(days=1)
  436. result = arr.take([-1, 1], allow_fill=True, fill_value=td1)
  437. assert result[0] == td1
  438. now = pd.Timestamp.now()
  439. with pytest.raises(ValueError):
  440. # fill_value Timestamp invalid
  441. arr.take([0, 1], allow_fill=True, fill_value=now)
  442. with pytest.raises(ValueError):
  443. # fill_value Period invalid
  444. arr.take([0, 1], allow_fill=True, fill_value=now.to_period('D'))
  445. class TestPeriodArray(SharedTests):
  446. index_cls = pd.PeriodIndex
  447. array_cls = PeriodArray
  448. def test_from_pi(self, period_index):
  449. pi = period_index
  450. arr = PeriodArray(pi)
  451. assert list(arr) == list(pi)
  452. # Check that Index.__new__ knows what to do with PeriodArray
  453. pi2 = pd.Index(arr)
  454. assert isinstance(pi2, pd.PeriodIndex)
  455. assert list(pi2) == list(arr)
  456. def test_astype_object(self, period_index):
  457. pi = period_index
  458. arr = PeriodArray(pi)
  459. asobj = arr.astype('O')
  460. assert isinstance(asobj, np.ndarray)
  461. assert asobj.dtype == 'O'
  462. assert list(asobj) == list(pi)
  463. @pytest.mark.parametrize('how', ['S', 'E'])
  464. def test_to_timestamp(self, how, period_index):
  465. pi = period_index
  466. arr = PeriodArray(pi)
  467. expected = DatetimeArray(pi.to_timestamp(how=how))
  468. result = arr.to_timestamp(how=how)
  469. assert isinstance(result, DatetimeArray)
  470. # placeholder until these become actual EA subclasses and we can use
  471. # an EA-specific tm.assert_ function
  472. tm.assert_index_equal(pd.Index(result), pd.Index(expected))
  473. @pytest.mark.parametrize('propname', PeriodArray._bool_ops)
  474. def test_bool_properties(self, period_index, propname):
  475. # in this case _bool_ops is just `is_leap_year`
  476. pi = period_index
  477. arr = PeriodArray(pi)
  478. result = getattr(arr, propname)
  479. expected = np.array(getattr(pi, propname))
  480. tm.assert_numpy_array_equal(result, expected)
  481. @pytest.mark.parametrize('propname', PeriodArray._field_ops)
  482. def test_int_properties(self, period_index, propname):
  483. pi = period_index
  484. arr = PeriodArray(pi)
  485. result = getattr(arr, propname)
  486. expected = np.array(getattr(pi, propname))
  487. tm.assert_numpy_array_equal(result, expected)
  488. def test_array_interface(self, period_index):
  489. arr = PeriodArray(period_index)
  490. # default asarray gives objects
  491. result = np.asarray(arr)
  492. expected = np.array(list(arr), dtype=object)
  493. tm.assert_numpy_array_equal(result, expected)
  494. # to object dtype (same as default)
  495. result = np.asarray(arr, dtype=object)
  496. tm.assert_numpy_array_equal(result, expected)
  497. # to other dtypes
  498. with pytest.raises(TypeError):
  499. np.asarray(arr, dtype='int64')
  500. with pytest.raises(TypeError):
  501. np.asarray(arr, dtype='float64')
  502. result = np.asarray(arr, dtype='S20')
  503. expected = np.asarray(arr).astype('S20')
  504. tm.assert_numpy_array_equal(result, expected)