From 5bf889921099722114893f5f5171bf66c6e7cbe0 Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Sun, 18 Feb 2024 17:24:15 +0000 Subject: [PATCH 1/8] 8683 TzInfo equality check based on offset --- src/input/datetime.rs | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/src/input/datetime.rs b/src/input/datetime.rs index 0a3cdf929..3b3c0b111 100644 --- a/src/input/datetime.rs +++ b/src/input/datetime.rs @@ -563,8 +563,23 @@ impl TzInfo { hasher.finish() } - fn __richcmp__(&self, other: &Self, op: CompareOp) -> bool { - op.matches(self.seconds.cmp(&other.seconds)) + fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult> { + let py = other.py(); + if other.is_instance_of::() { + let offset_delta = other.call_method1(intern!(py, "utcoffset"), (py.None().as_ref(py),))?; + let offset_seconds: f64 = offset_delta.call_method0(intern!(py, "total_seconds"))?.extract()?; + let offset = offset_seconds.round() as i32; + match op { + CompareOp::Lt => Ok((self.seconds < offset).into_py(py)), + CompareOp::Le => Ok((self.seconds <= offset).into_py(py)), + CompareOp::Eq => Ok((self.seconds == offset).into_py(py)), + CompareOp::Ne => Ok((self.seconds != offset).into_py(py)), + CompareOp::Gt => Ok((self.seconds > offset).into_py(py)), + CompareOp::Ge => Ok((self.seconds >= offset).into_py(py)), + } + } else { + Ok(py.NotImplemented()) + } } fn __deepcopy__(&self, py: Python, _memo: &PyDict) -> PyResult> { From bf929db24fb4b481c29a089a27b0db8846b098b3 Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Sun, 18 Feb 2024 18:05:51 +0000 Subject: [PATCH 2/8] 8683 tests TzInfo equality with derived class --- tests/test_tzinfo.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index cb67b737e..4e246e0c7 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -80,6 +80,7 @@ class TestTzInfo(unittest.TestCase): def setUp(self): self.ACDT = TzInfo(timedelta(hours=9.5).total_seconds()) self.EST = TzInfo(-timedelta(hours=5).total_seconds()) + self.UTC = TzInfo(timedelta(0).total_seconds()) self.DT = datetime(2010, 1, 1) def test_str(self): @@ -163,6 +164,13 @@ def test_comparison(self): self.assertFalse(tz <= SMALLEST) self.assertTrue(tz >= SMALLEST) + # offset based comparion tests for tzinfo derived classes like datetime.timezone. + utcdatetime = self.DT.replace(tzinfo=timezone.utc) + self.assertTrue(tz == utcdatetime.tzinfo) + estdatetime = self.DT.replace(tzinfo=timezone(-timedelta(hours=5))) + self.assertTrue(self.EST == estdatetime.tzinfo) + self.assertTrue(tz > estdatetime.tzinfo) + def test_copy(self): for tz in self.ACDT, self.EST: tz_copy = copy.copy(tz) From 51f2f5df293ad6fbd6e45cf552112d6bf825b9d1 Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Sun, 18 Feb 2024 18:25:48 +0000 Subject: [PATCH 3/8] 8683 self review reduce cmp code --- src/input/datetime.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/input/datetime.rs b/src/input/datetime.rs index 3b3c0b111..655e64aa6 100644 --- a/src/input/datetime.rs +++ b/src/input/datetime.rs @@ -569,14 +569,7 @@ impl TzInfo { let offset_delta = other.call_method1(intern!(py, "utcoffset"), (py.None().as_ref(py),))?; let offset_seconds: f64 = offset_delta.call_method0(intern!(py, "total_seconds"))?.extract()?; let offset = offset_seconds.round() as i32; - match op { - CompareOp::Lt => Ok((self.seconds < offset).into_py(py)), - CompareOp::Le => Ok((self.seconds <= offset).into_py(py)), - CompareOp::Eq => Ok((self.seconds == offset).into_py(py)), - CompareOp::Ne => Ok((self.seconds != offset).into_py(py)), - CompareOp::Gt => Ok((self.seconds > offset).into_py(py)), - CompareOp::Ge => Ok((self.seconds >= offset).into_py(py)), - } + Ok(op.matches(self.seconds.cmp(&offset)).into_py(py)) } else { Ok(py.NotImplemented()) } From 616e48fcc3f74347d13c21937d16cef2e9fe7c44 Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Tue, 20 Feb 2024 04:04:50 +0000 Subject: [PATCH 4/8] 8683 added notimplemented for zoneinfo --- src/input/datetime.rs | 5 ++++- tests/test_tzinfo.py | 3 +++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/input/datetime.rs b/src/input/datetime.rs index 655e64aa6..ebb5675f2 100644 --- a/src/input/datetime.rs +++ b/src/input/datetime.rs @@ -566,7 +566,10 @@ impl TzInfo { fn __richcmp__(&self, other: &PyAny, op: CompareOp) -> PyResult> { let py = other.py(); if other.is_instance_of::() { - let offset_delta = other.call_method1(intern!(py, "utcoffset"), (py.None().as_ref(py),))?; + let offset_delta = other.call_method1(intern!(py, "utcoffset"), (py.None(),))?; + if offset_delta.is_none() { + return Ok(py.NotImplemented()); + } let offset_seconds: f64 = offset_delta.call_method0(intern!(py, "total_seconds"))?.extract()?; let offset = offset_seconds.round() as i32; Ok(op.matches(self.seconds.cmp(&offset)).into_py(py)) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index 4e246e0c7..4a90f464b 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -4,6 +4,8 @@ import unittest from datetime import datetime, timedelta, timezone, tzinfo +from zoneinfo import ZoneInfo + from pydantic_core import SchemaValidator, TzInfo, core_schema @@ -170,6 +172,7 @@ def test_comparison(self): estdatetime = self.DT.replace(tzinfo=timezone(-timedelta(hours=5))) self.assertTrue(self.EST == estdatetime.tzinfo) self.assertTrue(tz > estdatetime.tzinfo) + self.assertFalse(tz == ZoneInfo('Europe/London')) def test_copy(self): for tz in self.ACDT, self.EST: From 604c33ad9c1c680d491167ffe556bad6ee25f81e Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Tue, 20 Feb 2024 04:39:00 +0000 Subject: [PATCH 5/8] 8683 added py version and os check for zoneinfo test --- tests/test_tzinfo.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index 4a90f464b..fd1c9f01d 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -1,13 +1,15 @@ import copy import functools import pickle +import sys import unittest from datetime import datetime, timedelta, timezone, tzinfo -from zoneinfo import ZoneInfo - from pydantic_core import SchemaValidator, TzInfo, core_schema +if sys.version_info > (3, 8): + from zoneinfo import ZoneInfo + class _ALWAYS_EQ: """ @@ -172,7 +174,8 @@ def test_comparison(self): estdatetime = self.DT.replace(tzinfo=timezone(-timedelta(hours=5))) self.assertTrue(self.EST == estdatetime.tzinfo) self.assertTrue(tz > estdatetime.tzinfo) - self.assertFalse(tz == ZoneInfo('Europe/London')) + if sys.version_info > (3, 8) and sys.platform == 'linux': + self.assertFalse(tz == ZoneInfo('Europe/London')) def test_copy(self): for tz in self.ACDT, self.EST: From 9e42571221f385a21303d179354cc419ac2f9d4e Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Tue, 20 Feb 2024 04:46:06 +0000 Subject: [PATCH 6/8] 8683 added py version check corrected --- tests/test_tzinfo.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index fd1c9f01d..e9159f098 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -7,7 +7,7 @@ from pydantic_core import SchemaValidator, TzInfo, core_schema -if sys.version_info > (3, 8): +if sys.version_info >= (3, 9): from zoneinfo import ZoneInfo @@ -174,7 +174,7 @@ def test_comparison(self): estdatetime = self.DT.replace(tzinfo=timezone(-timedelta(hours=5))) self.assertTrue(self.EST == estdatetime.tzinfo) self.assertTrue(tz > estdatetime.tzinfo) - if sys.version_info > (3, 8) and sys.platform == 'linux': + if sys.version_info >= (3, 9) and sys.platform == 'linux': self.assertFalse(tz == ZoneInfo('Europe/London')) def test_copy(self): From 88408f404b2dfe055b44ccc7dc8c4e1ec4fbd189 Mon Sep 17 00:00:00 2001 From: Sarbjot Singh Date: Tue, 20 Feb 2024 10:24:14 +0000 Subject: [PATCH 7/8] 8683 fixed TypeError test for zoneInfo --- tests/test_tzinfo.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index e9159f098..47882deac 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -175,7 +175,8 @@ def test_comparison(self): self.assertTrue(self.EST == estdatetime.tzinfo) self.assertTrue(tz > estdatetime.tzinfo) if sys.version_info >= (3, 9) and sys.platform == 'linux': - self.assertFalse(tz == ZoneInfo('Europe/London')) + with self.assertRaises(TypeError): + tz > ZoneInfo('Europe/London') def test_copy(self): for tz in self.ACDT, self.EST: From f099f3a2214fb2907e89a6055b810d7a15c1d925 Mon Sep 17 00:00:00 2001 From: David Hewitt Date: Tue, 20 Feb 2024 10:38:31 +0000 Subject: [PATCH 8/8] Update tests/test_tzinfo.py --- tests/test_tzinfo.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_tzinfo.py b/tests/test_tzinfo.py index 47882deac..949c9175d 100644 --- a/tests/test_tzinfo.py +++ b/tests/test_tzinfo.py @@ -175,6 +175,7 @@ def test_comparison(self): self.assertTrue(self.EST == estdatetime.tzinfo) self.assertTrue(tz > estdatetime.tzinfo) if sys.version_info >= (3, 9) and sys.platform == 'linux': + self.assertFalse(tz == ZoneInfo('Europe/London')) with self.assertRaises(TypeError): tz > ZoneInfo('Europe/London')