From 99bafdd5513c7091e88416c725690605d9e808f4 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 1 Oct 2018 21:38:12 -0500 Subject: [PATCH 1/7] Update type for PeriodDtype Removed unused IntervalDtypeType --- pandas/core/dtypes/common.py | 15 ++++++++------- pandas/core/dtypes/dtypes.py | 25 ++++++++----------------- pandas/tests/dtypes/test_common.py | 6 +++--- 3 files changed, 19 insertions(+), 27 deletions(-) diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index e2b9e246aee50..a3b61e2e1191e 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -4,12 +4,13 @@ from pandas.compat import (string_types, text_type, binary_type, PY3, PY36) from pandas._libs import algos, lib -from pandas._libs.tslibs import conversion +from pandas._libs.tslibs import conversion, Period +from pandas._libs.interval import Interval from pandas.core.dtypes.dtypes import ( registry, CategoricalDtype, CategoricalDtypeType, DatetimeTZDtype, - DatetimeTZDtypeType, PeriodDtype, PeriodDtypeType, IntervalDtype, - IntervalDtypeType, PandasExtensionDtype, ExtensionDtype, + DatetimeTZDtypeType, PeriodDtype, IntervalDtype, + PandasExtensionDtype, ExtensionDtype, _pandas_registry) from pandas.core.dtypes.generic import ( ABCCategorical, ABCPeriodIndex, ABCDatetimeIndex, ABCSeries, @@ -1907,18 +1908,18 @@ def _get_dtype_type(arr_or_dtype): elif isinstance(arr_or_dtype, DatetimeTZDtype): return DatetimeTZDtypeType elif isinstance(arr_or_dtype, IntervalDtype): - return IntervalDtypeType + return Interval elif isinstance(arr_or_dtype, PeriodDtype): - return PeriodDtypeType + return Period elif isinstance(arr_or_dtype, string_types): if is_categorical_dtype(arr_or_dtype): return CategoricalDtypeType elif is_datetime64tz_dtype(arr_or_dtype): return DatetimeTZDtypeType elif is_period_dtype(arr_or_dtype): - return PeriodDtypeType + return Period elif is_interval_dtype(arr_or_dtype): - return IntervalDtypeType + return Interval return _get_dtype_type(np.dtype(arr_or_dtype)) try: return arr_or_dtype.dtype.type diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index d879ded4f0f09..f731fd7016751 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -4,6 +4,7 @@ import numpy as np from pandas import compat from pandas.core.dtypes.generic import ABCIndexClass, ABCCategoricalIndex +from pandas._libs.tslibs import Period, NaT from .base import ExtensionDtype, _DtypeOpsMixin @@ -583,20 +584,13 @@ def __eq__(self, other): str(self.tz) == str(other.tz)) -class PeriodDtypeType(type): - """ - the type of PeriodDtype, this metaclass determines subclass ability - """ - pass - - class PeriodDtype(PandasExtensionDtype): """ A Period duck-typed class, suitable for holding a period with freq dtype. THIS IS NOT A REAL NUMPY DTYPE, but essentially a sub-class of np.int64. """ - type = PeriodDtypeType + type = Period kind = 'O' str = '|O08' base = np.dtype('O') @@ -666,11 +660,15 @@ def construct_from_string(cls, string): raise TypeError("could not construct PeriodDtype") def __unicode__(self): - return "period[{freq}]".format(freq=self.freq.freqstr) + return self.name @property def name(self): - return str(self) + return u"period[{freq}]".format(freq=self.freq.freqstr) + + @property + def na_value(self): + return NaT def __hash__(self): # make myself hashable @@ -705,13 +703,6 @@ def is_dtype(cls, dtype): return super(PeriodDtype, cls).is_dtype(dtype) -class IntervalDtypeType(type): - """ - the type of IntervalDtype, this metaclass determines subclass ability - """ - pass - - @register_extension_dtype class IntervalDtype(PandasExtensionDtype, ExtensionDtype): """ diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index a7a9faa9e77eb..b63498991dabc 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -611,9 +611,9 @@ def test__get_dtype_fails(input_param): ('datetime64[ns, Europe/London]', com.DatetimeTZDtypeType), (pd.SparseSeries([1, 2], dtype='int32'), np.int32), (pd.SparseSeries([1, 2], dtype='int32').dtype, np.int32), - (PeriodDtype(freq='D'), com.PeriodDtypeType), - ('period[D]', com.PeriodDtypeType), - (IntervalDtype(), com.IntervalDtypeType), + (PeriodDtype(freq='D'), pd.Period), + ('period[D]', pd.Period), + (IntervalDtype(), pd.Interval), (None, type(None)), (1, type(None)), (1.2, type(None)), From 8a8bdb05008ed52fe0eb8d4168347bc2af116b4a Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Mon, 1 Oct 2018 21:40:59 -0500 Subject: [PATCH 2/7] import at top --- pandas/core/dtypes/dtypes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index f731fd7016751..dbe0dda022637 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -5,6 +5,7 @@ from pandas import compat from pandas.core.dtypes.generic import ABCIndexClass, ABCCategoricalIndex from pandas._libs.tslibs import Period, NaT +from pandas._libs.interval import Interval from .base import ExtensionDtype, _DtypeOpsMixin @@ -791,7 +792,6 @@ def construct_from_string(cls, string): @property def type(self): - from pandas import Interval return Interval def __unicode__(self): From f07ab807e5eb393121197307de5718db429b71a8 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 2 Oct 2018 06:22:27 -0500 Subject: [PATCH 3/7] str, bytes --- pandas/core/dtypes/dtypes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index dbe0dda022637..0403b3fb28847 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -661,11 +661,11 @@ def construct_from_string(cls, string): raise TypeError("could not construct PeriodDtype") def __unicode__(self): - return self.name + return compat.text_type(self.name) @property def name(self): - return u"period[{freq}]".format(freq=self.freq.freqstr) + return str("period[{freq}]".format(freq=self.freq.freqstr)) @property def na_value(self): From 83db05c7ddec7a87ff77430ab686873b8a329a0f Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 2 Oct 2018 10:28:52 -0500 Subject: [PATCH 4/7] updates --- pandas/core/dtypes/base.py | 4 +++- pandas/core/dtypes/common.py | 4 ++-- pandas/core/dtypes/dtypes.py | 11 ++--------- pandas/tests/dtypes/test_common.py | 6 +++--- 4 files changed, 10 insertions(+), 15 deletions(-) diff --git a/pandas/core/dtypes/base.py b/pandas/core/dtypes/base.py index a552251ebbafa..5c9ba921226c0 100644 --- a/pandas/core/dtypes/base.py +++ b/pandas/core/dtypes/base.py @@ -175,7 +175,9 @@ def type(self): """The scalar type for the array, e.g. ``int`` It's expected ``ExtensionArray[item]`` returns an instance - of ``ExtensionDtype.type`` for scalar ``item``. + of ``ExtensionDtype.type`` for scalar ``item``, assuming + that value is valid (not NA). NA values do not need to be + instances of `type`. """ raise AbstractMethodError(self) diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index a3b61e2e1191e..cfa25d04a3201 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -4,7 +4,7 @@ from pandas.compat import (string_types, text_type, binary_type, PY3, PY36) from pandas._libs import algos, lib -from pandas._libs.tslibs import conversion, Period +from pandas._libs.tslibs import conversion, Period, Timestamp from pandas._libs.interval import Interval from pandas.core.dtypes.dtypes import ( @@ -1915,7 +1915,7 @@ def _get_dtype_type(arr_or_dtype): if is_categorical_dtype(arr_or_dtype): return CategoricalDtypeType elif is_datetime64tz_dtype(arr_or_dtype): - return DatetimeTZDtypeType + return Timestmap elif is_period_dtype(arr_or_dtype): return Period elif is_interval_dtype(arr_or_dtype): diff --git a/pandas/core/dtypes/dtypes.py b/pandas/core/dtypes/dtypes.py index 0403b3fb28847..944365232db65 100644 --- a/pandas/core/dtypes/dtypes.py +++ b/pandas/core/dtypes/dtypes.py @@ -4,7 +4,7 @@ import numpy as np from pandas import compat from pandas.core.dtypes.generic import ABCIndexClass, ABCCategoricalIndex -from pandas._libs.tslibs import Period, NaT +from pandas._libs.tslibs import Period, NaT, Timestamp from pandas._libs.interval import Interval from .base import ExtensionDtype, _DtypeOpsMixin @@ -471,13 +471,6 @@ def _is_boolean(self): return is_bool_dtype(self.categories) -class DatetimeTZDtypeType(type): - """ - the type of DatetimeTZDtype, this metaclass determines subclass ability - """ - pass - - class DatetimeTZDtype(PandasExtensionDtype): """ @@ -487,7 +480,7 @@ class DatetimeTZDtype(PandasExtensionDtype): THIS IS NOT A REAL NUMPY DTYPE, but essentially a sub-class of np.datetime64[ns] """ - type = DatetimeTZDtypeType + type = Timestamp kind = 'M' str = '|M8[ns]' num = 101 diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index b63498991dabc..e5cb650440b91 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -605,10 +605,10 @@ def test__get_dtype_fails(input_param): (pd.DatetimeIndex([1, 2]), np.datetime64), (pd.DatetimeIndex([1, 2]).dtype, np.datetime64), (' Date: Tue, 2 Oct 2018 10:32:22 -0500 Subject: [PATCH 5/7] doc note --- doc/source/whatsnew/v0.24.0.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v0.24.0.txt b/doc/source/whatsnew/v0.24.0.txt index b71edcf1f6f51..1973698016680 100644 --- a/doc/source/whatsnew/v0.24.0.txt +++ b/doc/source/whatsnew/v0.24.0.txt @@ -505,6 +505,7 @@ ExtensionType Changes - :meth:`Series.astype` and :meth:`DataFrame.astype` now dispatch to :meth:`ExtensionArray.astype` (:issue:`21185:`). - Slicing a single row of a ``DataFrame`` with multiple ExtensionArrays of the same type now preserves the dtype, rather than coercing to object (:issue:`22784`) - Added :meth:`pandas.api.types.register_extension_dtype` to register an extension type with pandas (:issue:`22664`) +- Updated the ``.type`` attribute for ``PeriodDtype``, ``DatetimeTZDtype``, and ``IntervalDtype`` to be instances of the dtype (``Period``, ``Timestamp``, and ``Interval`` respectively) (:issue:`22938`) .. _whatsnew_0240.api.incompatibilities: From d7a8e1b8686024b3c891d01ce267ccbfd1beabb9 Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 2 Oct 2018 10:57:56 -0500 Subject: [PATCH 6/7] Fixed --- pandas/core/dtypes/common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/core/dtypes/common.py b/pandas/core/dtypes/common.py index cfa25d04a3201..7c91e62cc9876 100644 --- a/pandas/core/dtypes/common.py +++ b/pandas/core/dtypes/common.py @@ -9,7 +9,7 @@ from pandas.core.dtypes.dtypes import ( registry, CategoricalDtype, CategoricalDtypeType, DatetimeTZDtype, - DatetimeTZDtypeType, PeriodDtype, IntervalDtype, + PeriodDtype, IntervalDtype, PandasExtensionDtype, ExtensionDtype, _pandas_registry) from pandas.core.dtypes.generic import ( @@ -1906,7 +1906,7 @@ def _get_dtype_type(arr_or_dtype): elif isinstance(arr_or_dtype, CategoricalDtype): return CategoricalDtypeType elif isinstance(arr_or_dtype, DatetimeTZDtype): - return DatetimeTZDtypeType + return Timestamp elif isinstance(arr_or_dtype, IntervalDtype): return Interval elif isinstance(arr_or_dtype, PeriodDtype): @@ -1915,7 +1915,7 @@ def _get_dtype_type(arr_or_dtype): if is_categorical_dtype(arr_or_dtype): return CategoricalDtypeType elif is_datetime64tz_dtype(arr_or_dtype): - return Timestmap + return Timestamp elif is_period_dtype(arr_or_dtype): return Period elif is_interval_dtype(arr_or_dtype): From d65980ec629558bfc205316ce6be01daecb54a9d Mon Sep 17 00:00:00 2001 From: Tom Augspurger Date: Tue, 2 Oct 2018 11:46:38 -0500 Subject: [PATCH 7/7] typo --- pandas/tests/dtypes/test_common.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pandas/tests/dtypes/test_common.py b/pandas/tests/dtypes/test_common.py index e5cb650440b91..f87c51a4ee16b 100644 --- a/pandas/tests/dtypes/test_common.py +++ b/pandas/tests/dtypes/test_common.py @@ -605,10 +605,10 @@ def test__get_dtype_fails(input_param): (pd.DatetimeIndex([1, 2]), np.datetime64), (pd.DatetimeIndex([1, 2]).dtype, np.datetime64), ('