test_constructors.py 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174
  1. from datetime import datetime
  2. import sys
  3. import numpy as np
  4. import pytest
  5. from pandas.compat import PYPY
  6. import pandas as pd
  7. from pandas import (
  8. DataFrame,
  9. Index,
  10. Series,
  11. )
  12. import pandas._testing as tm
  13. from pandas.core.accessor import PandasDelegate
  14. from pandas.core.base import (
  15. NoNewAttributesMixin,
  16. PandasObject,
  17. )
  18. def series_via_frame_from_dict(x, **kwargs):
  19. return DataFrame({"a": x}, **kwargs)["a"]
  20. def series_via_frame_from_scalar(x, **kwargs):
  21. return DataFrame(x, **kwargs)[0]
  22. @pytest.fixture(
  23. params=[
  24. Series,
  25. series_via_frame_from_dict,
  26. series_via_frame_from_scalar,
  27. Index,
  28. ],
  29. ids=["Series", "DataFrame-dict", "DataFrame-array", "Index"],
  30. )
  31. def constructor(request):
  32. return request.param
  33. class TestPandasDelegate:
  34. class Delegator:
  35. _properties = ["prop"]
  36. _methods = ["test_method"]
  37. def _set_prop(self, value):
  38. self.prop = value
  39. def _get_prop(self):
  40. return self.prop
  41. prop = property(_get_prop, _set_prop, doc="foo property")
  42. def test_method(self, *args, **kwargs):
  43. """a test method"""
  44. class Delegate(PandasDelegate, PandasObject):
  45. def __init__(self, obj) -> None:
  46. self.obj = obj
  47. def test_invalid_delegation(self):
  48. # these show that in order for the delegation to work
  49. # the _delegate_* methods need to be overridden to not raise
  50. # a TypeError
  51. self.Delegate._add_delegate_accessors(
  52. delegate=self.Delegator,
  53. accessors=self.Delegator._properties,
  54. typ="property",
  55. )
  56. self.Delegate._add_delegate_accessors(
  57. delegate=self.Delegator, accessors=self.Delegator._methods, typ="method"
  58. )
  59. delegate = self.Delegate(self.Delegator())
  60. msg = "You cannot access the property prop"
  61. with pytest.raises(TypeError, match=msg):
  62. delegate.prop
  63. msg = "The property prop cannot be set"
  64. with pytest.raises(TypeError, match=msg):
  65. delegate.prop = 5
  66. msg = "You cannot access the property prop"
  67. with pytest.raises(TypeError, match=msg):
  68. delegate.prop
  69. @pytest.mark.skipif(PYPY, reason="not relevant for PyPy")
  70. def test_memory_usage(self):
  71. # Delegate does not implement memory_usage.
  72. # Check that we fall back to in-built `__sizeof__`
  73. # GH 12924
  74. delegate = self.Delegate(self.Delegator())
  75. sys.getsizeof(delegate)
  76. class TestNoNewAttributesMixin:
  77. def test_mixin(self):
  78. class T(NoNewAttributesMixin):
  79. pass
  80. t = T()
  81. assert not hasattr(t, "__frozen")
  82. t.a = "test"
  83. assert t.a == "test"
  84. t._freeze()
  85. assert "__frozen" in dir(t)
  86. assert getattr(t, "__frozen")
  87. msg = "You cannot add any new attribute"
  88. with pytest.raises(AttributeError, match=msg):
  89. t.b = "test"
  90. assert not hasattr(t, "b")
  91. class TestConstruction:
  92. # test certain constructor behaviours on dtype inference across Series,
  93. # Index and DataFrame
  94. @pytest.mark.parametrize(
  95. "a",
  96. [
  97. np.array(["2263-01-01"], dtype="datetime64[D]"),
  98. np.array([datetime(2263, 1, 1)], dtype=object),
  99. np.array([np.datetime64("2263-01-01", "D")], dtype=object),
  100. np.array(["2263-01-01"], dtype=object),
  101. ],
  102. ids=[
  103. "datetime64[D]",
  104. "object-datetime.datetime",
  105. "object-numpy-scalar",
  106. "object-string",
  107. ],
  108. )
  109. def test_constructor_datetime_outofbound(self, a, constructor):
  110. # GH-26853 (+ bug GH-26206 out of bound non-ns unit)
  111. # No dtype specified (dtype inference)
  112. # datetime64[non-ns] raise error, other cases result in object dtype
  113. # and preserve original data
  114. if a.dtype.kind == "M":
  115. # Can't fit in nanosecond bounds -> get the nearest supported unit
  116. result = constructor(a)
  117. assert result.dtype == "M8[s]"
  118. else:
  119. result = constructor(a)
  120. assert result.dtype == "object"
  121. tm.assert_numpy_array_equal(result.to_numpy(), a)
  122. # Explicit dtype specified
  123. # Forced conversion fails for all -> all cases raise error
  124. msg = "Out of bounds|Out of bounds .* present at position 0"
  125. with pytest.raises(pd.errors.OutOfBoundsDatetime, match=msg):
  126. constructor(a, dtype="datetime64[ns]")
  127. def test_constructor_datetime_nonns(self, constructor):
  128. arr = np.array(["2020-01-01T00:00:00.000000"], dtype="datetime64[us]")
  129. dta = pd.core.arrays.DatetimeArray._simple_new(arr, dtype=arr.dtype)
  130. expected = constructor(dta)
  131. assert expected.dtype == arr.dtype
  132. result = constructor(arr)
  133. tm.assert_equal(result, expected)
  134. # https://github.com/pandas-dev/pandas/issues/34843
  135. arr.flags.writeable = False
  136. result = constructor(arr)
  137. tm.assert_equal(result, expected)