From cbea9c3994b0f6592fb6217969f0921148edc6e4 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Sun, 22 Dec 2019 22:35:21 +0200 Subject: [PATCH 1/7] COMPAT: Added 'Timestamp.fromisocalendar' --- pandas/_libs/tslibs/nattype.pyx | 7 +++++++ pandas/_libs/tslibs/timestamps.pyx | 17 +++++++++++++++++ pandas/tests/scalar/test_nat.py | 2 -- pandas/tests/scalar/timestamp/test_timestamp.py | 13 +++++++++++++ 4 files changed, 37 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 76a694c64e1fb..a24e22a7bb396 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -467,7 +467,14 @@ class NaTType(_NaT): Return a new Timestamp representing UTC day and time. """ ) + fromisocalendar = _make_error_func('fromisocalendar', # noqa:E128 + """ + Timestamp.fromisocalendar(year, week, day) + Return a new Timestamp corresponding to the + ISO calendar date specified by year, week and day. + """ + ) timestamp = _make_error_func('timestamp', # noqa:E128 """Return POSIX timestamp as float.""") diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 86a9d053730b8..7f004ed412585 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -336,6 +336,23 @@ class Timestamp(_Timestamp): """ return cls(datetime.combine(date, time)) + @classmethod + def fromisocalendar(cls, year, week, day): + """ + Timestamp.fromisocalendar(year, week, day) + + Return a new Timestamp corresponding to the + ISO calendar date specified by year, week and day. + """ + import pandas.compat as compat + + if not compat.PY38: + raise NotImplementedError( + "'fromisocalendar' is not supported for versions earlier than 3.8" + ) + + return cls(datetime.fromisocalendar(year, week, day)) + def __new__( cls, object ts_input=_no_input, diff --git a/pandas/tests/scalar/test_nat.py b/pandas/tests/scalar/test_nat.py index e709db980b721..301c606e566d0 100644 --- a/pandas/tests/scalar/test_nat.py +++ b/pandas/tests/scalar/test_nat.py @@ -297,8 +297,6 @@ def test_overlap_public_nat_methods(klass, expected): # "fromisoformat" was introduced in 3.7 if klass is Timestamp and not compat.PY37: expected.remove("fromisoformat") - if klass is Timestamp and not compat.PY38: - expected.remove("fromisocalendar") assert _get_overlap_public_nat_methods(klass) == expected diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index 25609cb852ed4..d0973f0266ffb 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -14,6 +14,7 @@ from pandas._libs.tslibs import conversion from pandas._libs.tslibs.timezones import dateutil_gettz as gettz, get_timezone +import pandas.compat as compat from pandas.compat.numpy import np_datetime64_compat from pandas.errors import OutOfBoundsDatetime import pandas.util._test_decorators as td @@ -700,6 +701,18 @@ class SubDatetime(datetime): expected = Timestamp(2000, 1, 1) assert result == expected + @pytest.mark.skipif( + not compat.PY38, + reason="datetime.fromisocalendar was added in Python version 3.8", + ) + def test_constructor_fromisocalendar(self): + # GH 30395 + expected_timestamp = Timestamp("2000-01-03 00:00:00") + expected_stdlib = datetime.fromisocalendar(2000, 1, 1) + result = Timestamp.fromisocalendar(2000, 1, 1) + assert result == expected_timestamp + assert result == expected_stdlib + class TestTimestamp: def test_tz(self): From 3f37a977c4d8dc82c6f91ef0128caa99792a3fcc Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Tue, 24 Dec 2019 17:55:44 +0200 Subject: [PATCH 2/7] Added full docstring --- pandas/_libs/tslibs/nattype.pyx | 22 ++++++++++++++++++++++ pandas/_libs/tslibs/timestamps.pyx | 22 ++++++++++++++++++++++ 2 files changed, 44 insertions(+) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index a24e22a7bb396..b4a671745a45c 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -473,6 +473,28 @@ class NaTType(_NaT): Return a new Timestamp corresponding to the ISO calendar date specified by year, week and day. + + Parameters + ---------- + year: int + Representing a year. + week : int + Value between 1-53, representing a week in a year. + day : int + Value between 1-7, representing a day in the week. + + Returns + ------- + Timestamp + + Raises + ------ + NotImplementedError + If the running platform is a Python version earlier than 3.8 + + Notes + ----- + `week` can have the value of 53, only when year is a leap year. """ ) timestamp = _make_error_func('timestamp', # noqa:E128 diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 7f004ed412585..68394a67f514e 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -343,6 +343,28 @@ class Timestamp(_Timestamp): Return a new Timestamp corresponding to the ISO calendar date specified by year, week and day. + + Parameters + ---------- + year: int + Representing a year. + week : int + Value between 1-53, representing a week in a year. + day : int + Value between 1-7, representing a day in the week. + + Returns + ------- + Timestamp + + Raises + ------ + NotImplementedError + If the running platform is a Python version earlier than 3.8 + + Notes + ----- + `week` can have the value of 53, only when year is a leap year. """ import pandas.compat as compat From e4696b113b567dec4aed38970616920d803d6b1e Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Tue, 31 Dec 2019 15:15:24 +0200 Subject: [PATCH 3/7] Fixed tests --- pandas/_libs/tslibs/nattype.pyx | 32 ++------------- pandas/_libs/tslibs/timestamps.pyx | 39 ------------------- pandas/tests/scalar/test_nat.py | 1 + .../tests/scalar/timestamp/test_timestamp.py | 1 + 4 files changed, 5 insertions(+), 68 deletions(-) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index b4a671745a45c..4e6080d1e7fcc 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -426,6 +426,9 @@ class NaTType(_NaT): toordinal = _make_error_func('toordinal', datetime) tzname = _make_error_func('tzname', datetime) utcoffset = _make_error_func('utcoffset', datetime) + fromisocalendar = _make_error_func( + 'fromisocalendar', datetime.fromisocalendar.__doc__ + ) # ---------------------------------------------------------------------- # The remaining methods have docstrings copy/pasted from the analogous @@ -467,36 +470,7 @@ class NaTType(_NaT): Return a new Timestamp representing UTC day and time. """ ) - fromisocalendar = _make_error_func('fromisocalendar', # noqa:E128 - """ - Timestamp.fromisocalendar(year, week, day) - - Return a new Timestamp corresponding to the - ISO calendar date specified by year, week and day. - - Parameters - ---------- - year: int - Representing a year. - week : int - Value between 1-53, representing a week in a year. - day : int - Value between 1-7, representing a day in the week. - - Returns - ------- - Timestamp - Raises - ------ - NotImplementedError - If the running platform is a Python version earlier than 3.8 - - Notes - ----- - `week` can have the value of 53, only when year is a leap year. - """ - ) timestamp = _make_error_func('timestamp', # noqa:E128 """Return POSIX timestamp as float.""") diff --git a/pandas/_libs/tslibs/timestamps.pyx b/pandas/_libs/tslibs/timestamps.pyx index 68394a67f514e..86a9d053730b8 100644 --- a/pandas/_libs/tslibs/timestamps.pyx +++ b/pandas/_libs/tslibs/timestamps.pyx @@ -336,45 +336,6 @@ class Timestamp(_Timestamp): """ return cls(datetime.combine(date, time)) - @classmethod - def fromisocalendar(cls, year, week, day): - """ - Timestamp.fromisocalendar(year, week, day) - - Return a new Timestamp corresponding to the - ISO calendar date specified by year, week and day. - - Parameters - ---------- - year: int - Representing a year. - week : int - Value between 1-53, representing a week in a year. - day : int - Value between 1-7, representing a day in the week. - - Returns - ------- - Timestamp - - Raises - ------ - NotImplementedError - If the running platform is a Python version earlier than 3.8 - - Notes - ----- - `week` can have the value of 53, only when year is a leap year. - """ - import pandas.compat as compat - - if not compat.PY38: - raise NotImplementedError( - "'fromisocalendar' is not supported for versions earlier than 3.8" - ) - - return cls(datetime.fromisocalendar(year, week, day)) - def __new__( cls, object ts_input=_no_input, diff --git a/pandas/tests/scalar/test_nat.py b/pandas/tests/scalar/test_nat.py index 301c606e566d0..213e6630ff098 100644 --- a/pandas/tests/scalar/test_nat.py +++ b/pandas/tests/scalar/test_nat.py @@ -123,6 +123,7 @@ def test_round_nat(klass, method, freq): "dst", "fromordinal", "fromtimestamp", + "fromisocalendar", "isocalendar", "strftime", "strptime", diff --git a/pandas/tests/scalar/timestamp/test_timestamp.py b/pandas/tests/scalar/timestamp/test_timestamp.py index d0973f0266ffb..10857f6a5e789 100644 --- a/pandas/tests/scalar/timestamp/test_timestamp.py +++ b/pandas/tests/scalar/timestamp/test_timestamp.py @@ -712,6 +712,7 @@ def test_constructor_fromisocalendar(self): result = Timestamp.fromisocalendar(2000, 1, 1) assert result == expected_timestamp assert result == expected_stdlib + assert isinstance(result, Timestamp) class TestTimestamp: From e32260397fbd1708cdd9f0ea366a0a41d086cf3d Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 1 Jan 2020 15:55:35 +0200 Subject: [PATCH 4/7] Put fromisocalendar in PY38 block --- pandas/_libs/tslibs/nattype.pyx | 9 ++++++--- pandas/tests/scalar/test_nat.py | 8 ++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 4e6080d1e7fcc..9620ab9b54498 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -19,6 +19,8 @@ from pandas._libs.tslibs.util cimport ( get_nat, is_integer_object, is_float_object, is_datetime64_object, is_timedelta64_object) +import pandas.compat as compat + # ---------------------------------------------------------------------- # Constants nat_strings = {'NaT', 'nat', 'NAT', 'nan', 'NaN', 'NAN'} @@ -426,9 +428,10 @@ class NaTType(_NaT): toordinal = _make_error_func('toordinal', datetime) tzname = _make_error_func('tzname', datetime) utcoffset = _make_error_func('utcoffset', datetime) - fromisocalendar = _make_error_func( - 'fromisocalendar', datetime.fromisocalendar.__doc__ - ) + + # "fromisocalendar" was introduced in 3.8 + if compat.PY38: + fromisocalendar = _make_error_func('fromisocalendar', datetime) # ---------------------------------------------------------------------- # The remaining methods have docstrings copy/pasted from the analogous diff --git a/pandas/tests/scalar/test_nat.py b/pandas/tests/scalar/test_nat.py index 213e6630ff098..0f5109f108eac 100644 --- a/pandas/tests/scalar/test_nat.py +++ b/pandas/tests/scalar/test_nat.py @@ -141,6 +141,10 @@ def test_round_nat(klass, method, freq): ], ) def test_nat_methods_raise(method): + # "fromisocalendar" was introduced in 3.8 + if method == "fromisocalendar" and not compat.PY38: + method.remove("fromisocalendar") + # see gh-9513, gh-17329 msg = f"NaTType does not support {method}" @@ -299,6 +303,10 @@ def test_overlap_public_nat_methods(klass, expected): if klass is Timestamp and not compat.PY37: expected.remove("fromisoformat") + # "fromisocalendar" was introduced in 3.8 + if klass is Timestamp and not compat.PY38: + expected.remove("fromisocalendar") + assert _get_overlap_public_nat_methods(klass) == expected From ad9c41135c402576a46d030175757f153fdf826f Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Wed, 1 Jan 2020 21:06:55 +0200 Subject: [PATCH 5/7] skip 'fromisocalendar' method if not in python 3.8 and above --- pandas/tests/scalar/test_nat.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/pandas/tests/scalar/test_nat.py b/pandas/tests/scalar/test_nat.py index 0f5109f108eac..837535dc35794 100644 --- a/pandas/tests/scalar/test_nat.py +++ b/pandas/tests/scalar/test_nat.py @@ -123,7 +123,13 @@ def test_round_nat(klass, method, freq): "dst", "fromordinal", "fromtimestamp", - "fromisocalendar", + pytest.param( + "fromisocalendar", + marks=pytest.mark.skipif( + not compat.PY38, + reason="'fromisocalendar' was added in stdlib datetime in python 3.8", + ), + ), "isocalendar", "strftime", "strptime", @@ -141,10 +147,6 @@ def test_round_nat(klass, method, freq): ], ) def test_nat_methods_raise(method): - # "fromisocalendar" was introduced in 3.8 - if method == "fromisocalendar" and not compat.PY38: - method.remove("fromisocalendar") - # see gh-9513, gh-17329 msg = f"NaTType does not support {method}" From a06dbca6a3460791ef265d1c0032ef9a4cfac694 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Sun, 5 Jan 2020 09:27:52 +0200 Subject: [PATCH 6/7] Replaced compat.PY38 with cpython.version.PY_MINOR_VERSION --- pandas/_libs/tslibs/nattype.pyx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/pandas/_libs/tslibs/nattype.pyx b/pandas/_libs/tslibs/nattype.pyx index 9620ab9b54498..67c0f0cc33ab8 100644 --- a/pandas/_libs/tslibs/nattype.pyx +++ b/pandas/_libs/tslibs/nattype.pyx @@ -5,6 +5,9 @@ from cpython.object cimport ( from cpython.datetime cimport (datetime, PyDateTime_Check, PyDelta_Check, PyDateTime_IMPORT) + +from cpython.version cimport PY_MINOR_VERSION + PyDateTime_IMPORT import numpy as np @@ -19,7 +22,6 @@ from pandas._libs.tslibs.util cimport ( get_nat, is_integer_object, is_float_object, is_datetime64_object, is_timedelta64_object) -import pandas.compat as compat # ---------------------------------------------------------------------- # Constants @@ -430,7 +432,7 @@ class NaTType(_NaT): utcoffset = _make_error_func('utcoffset', datetime) # "fromisocalendar" was introduced in 3.8 - if compat.PY38: + if PY_MINOR_VERSION >= 8: fromisocalendar = _make_error_func('fromisocalendar', datetime) # ---------------------------------------------------------------------- From c8ad230289f9af99e8ebe5278c22ab969b9a4a49 Mon Sep 17 00:00:00 2001 From: MomIsBestFriend <> Date: Sun, 5 Jan 2020 09:33:26 +0200 Subject: [PATCH 7/7] Added what's new note --- doc/source/whatsnew/v1.0.0.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/whatsnew/v1.0.0.rst b/doc/source/whatsnew/v1.0.0.rst index 014bd22aa2dab..d9dd3b803a36e 100755 --- a/doc/source/whatsnew/v1.0.0.rst +++ b/doc/source/whatsnew/v1.0.0.rst @@ -227,6 +227,7 @@ Other enhancements - Added new writer for exporting Stata dta files in version 118, ``StataWriter118``. This format supports exporting strings containing Unicode characters (:issue:`23573`) - :meth:`Series.map` now accepts ``collections.abc.Mapping`` subclasses as a mapper (:issue:`29733`) - The ``pandas.datetime`` class is now deprecated. Import from ``datetime`` instead (:issue:`30296`) +- :meth:`Timestamp.fromisocalendar` is now compatible with python 3.8 and above (:issue:`28115`)