From b7abb9bb698d4d391da7f69ca983164f51d9a567 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafael=20Weing=C3=A4rtner?= Date: Wed, 19 Aug 2020 20:03:51 -0300 Subject: [PATCH] Replace tz.UTC with dateutil.tz.tzutc() As discussed in https://review.opendev.org/#/c/742477/, this patch replaces the use of `tz.UTC` with `dateutil.tz.tzutc()` Also add python-dateutil to requirements.txt, using the same minimum version as several other OpenStack projects, including nova. Change-Id: I4da9e8854a571058e48c2f51c1d340bc135cfe2b --- cloudkitty/tests/collectors/test_gnocchi.py | 4 +-- cloudkitty/tests/gabbi/fixtures.py | 6 ++-- .../storage/v2/elasticsearch/test_client.py | 4 +-- cloudkitty/tests/storage/v2/test_influxdb.py | 7 +++-- cloudkitty/tests/test_dataframe.py | 28 +++++++++---------- cloudkitty/tests/utils_tests/test_json.py | 2 +- cloudkitty/tests/utils_tests/test_tz.py | 18 ++++++------ cloudkitty/utils/tz.py | 13 +++++---- lower-constraints.txt | 1 + ...ateutil-tz-utc-usage-1350c00be3fadde7.yaml | 5 ++++ requirements.txt | 1 + 11 files changed, 49 insertions(+), 40 deletions(-) create mode 100644 releasenotes/notes/remove-dateutil-tz-utc-usage-1350c00be3fadde7.yaml diff --git a/cloudkitty/tests/collectors/test_gnocchi.py b/cloudkitty/tests/collectors/test_gnocchi.py index e8375e60..4bf420e3 100644 --- a/cloudkitty/tests/collectors/test_gnocchi.py +++ b/cloudkitty/tests/collectors/test_gnocchi.py @@ -157,8 +157,8 @@ class GnocchiCollectorAggregationOperationTest(tests.TestCase): def setUp(self): super(GnocchiCollectorAggregationOperationTest, self).setUp() self.conf.set_override('collector', 'gnocchi', 'collect') - self.start = datetime.datetime(2019, 1, 1, tzinfo=tz.UTC) - self.end = datetime.datetime(2019, 1, 1, 1, tzinfo=tz.UTC) + self.start = datetime.datetime(2019, 1, 1, tzinfo=tz.tzutc()) + self.end = datetime.datetime(2019, 1, 1, 1, tzinfo=tz.tzutc()) def do_test(self, expected_op, extra_args=None): conf = { diff --git a/cloudkitty/tests/gabbi/fixtures.py b/cloudkitty/tests/gabbi/fixtures.py index 53d86f90..65c2e96d 100644 --- a/cloudkitty/tests/gabbi/fixtures.py +++ b/cloudkitty/tests/gabbi/fixtures.py @@ -54,7 +54,7 @@ from cloudkitty import utils as ck_utils from cloudkitty.utils import tz as tzutils -INITIAL_DT = datetime.datetime(2015, 1, 1, tzinfo=tz.UTC) +INITIAL_DT = datetime.datetime(2015, 1, 1, tzinfo=tz.tzutc()) class UUIDFixture(fixture.GabbiFixture): @@ -377,7 +377,7 @@ class StorageDataFixture(BaseStorageDataFixture): class NowStorageDataFixture(BaseStorageDataFixture): def initialize_data(self): - dt = tzutils.get_month_start(naive=True).replace(tzinfo=tz.UTC) + dt = tzutils.get_month_start(naive=True).replace(tzinfo=tz.tzutc()) hour_delta = datetime.timedelta(seconds=3600) limit = dt + hour_delta * 12 while dt < limit: @@ -501,7 +501,7 @@ class InfluxStorageDataFixture(StorageDataFixture): class UTCFixture(fixture.GabbiFixture): """Set the local timezone to UTC""" def start_fixture(self): - self._tzmock = mock.patch('cloudkitty.utils.tz._LOCAL_TZ', tz.UTC) + self._tzmock = mock.patch('cloudkitty.utils.tz._LOCAL_TZ', tz.tzutc()) self._tzmock.start() def stop_fixture(self): diff --git a/cloudkitty/tests/storage/v2/elasticsearch/test_client.py b/cloudkitty/tests/storage/v2/elasticsearch/test_client.py index ac5dae05..8948be91 100644 --- a/cloudkitty/tests/storage/v2/elasticsearch/test_client.py +++ b/cloudkitty/tests/storage/v2/elasticsearch/test_client.py @@ -38,8 +38,8 @@ class TestElasticsearchClient(unittest.TestCase): self.assertEqual(self.client._build_must(None, None, None, None), []) def test_build_must_with_start_end(self): - start = datetime.datetime(2019, 8, 30, tzinfo=tz.UTC) - end = datetime.datetime(2019, 8, 31, tzinfo=tz.UTC) + start = datetime.datetime(2019, 8, 30, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 8, 31, tzinfo=tz.tzutc()) self.assertEqual( self.client._build_must(start, end, None, None), [{'range': {'start': {'gte': '2019-08-30T00:00:00+00:00'}}}, diff --git a/cloudkitty/tests/storage/v2/test_influxdb.py b/cloudkitty/tests/storage/v2/test_influxdb.py index 54dbb479..7aed06fa 100644 --- a/cloudkitty/tests/storage/v2/test_influxdb.py +++ b/cloudkitty/tests/storage/v2/test_influxdb.py @@ -42,7 +42,7 @@ class TestInfluxDBStorage(TestCase): 'two': '2', '1': 'one', '2': 'two', - 'time': datetime(2019, 1, 1, tzinfo=tz.UTC).isoformat(), + 'time': datetime(2019, 1, 1, tzinfo=tz.tzutc()).isoformat(), } def test_point_to_dataframe_entry_valid_point(self): @@ -81,10 +81,11 @@ class TestInfluxDBStorage(TestCase): self.assertEqual(len(dataframes), 3) for idx, frame in enumerate(dataframes): - self.assertEqual(frame.start, datetime(2019, 1, 1, tzinfo=tz.UTC)) + self.assertEqual( + frame.start, datetime(2019, 1, 1, tzinfo=tz.tzutc())) delta = timedelta(seconds=(idx + 1) * 100) self.assertEqual(frame.end, - datetime(2019, 1, 1, tzinfo=tz.UTC) + delta) + datetime(2019, 1, 1, tzinfo=tz.tzutc()) + delta) typelist = list(frame.itertypes()) self.assertEqual(len(typelist), 1) type_, points = typelist[0] diff --git a/cloudkitty/tests/test_dataframe.py b/cloudkitty/tests/test_dataframe.py index 1f4ab690..1ca85dd3 100644 --- a/cloudkitty/tests/test_dataframe.py +++ b/cloudkitty/tests/test_dataframe.py @@ -154,8 +154,8 @@ class TestDataPoint(unittest.TestCase): class TestDataFrame(unittest.TestCase): def test_dataframe_add_points(self): - start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.UTC) - end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.UTC) + start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.tzutc()) df = dataframe.DataFrame(start=start, end=end) a_points = [dataframe.DataPoint(**TestDataPoint.default_params) for _ in range(2)] @@ -183,15 +183,15 @@ class TestDataFrame(unittest.TestCase): }) def test_properties(self): - start = datetime.datetime(2019, 6, 1, tzinfo=tz.UTC) - end = datetime.datetime(2019, 6, 1, 1, tzinfo=tz.UTC) + start = datetime.datetime(2019, 6, 1, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 6, 1, 1, tzinfo=tz.tzutc()) df = dataframe.DataFrame(start=start, end=end) self.assertEqual(df.start, start) self.assertEqual(df.end, end) def test_json(self): - start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.UTC) - end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.UTC) + start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.tzutc()) df = dataframe.DataFrame(start=start, end=end) a_points = [dataframe.DataPoint(**TestDataPoint.default_params) for _ in range(2)] @@ -217,8 +217,8 @@ class TestDataFrame(unittest.TestCase): }))) def test_from_dict_valid_dict(self): - start = datetime.datetime(2019, 1, 2, 12, tzinfo=tz.UTC) - end = datetime.datetime(2019, 1, 2, 13, tzinfo=tz.UTC) + start = datetime.datetime(2019, 1, 2, 12, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 1, 2, 13, tzinfo=tz.tzutc()) point = dataframe.DataPoint( 'unit', 0, 0, {'g_one': 'one'}, {'m_two': 'two'}) usage = {'metric_x': [point]} @@ -232,8 +232,8 @@ class TestDataFrame(unittest.TestCase): ) def test_from_dict_valid_dict_date_as_str(self): - start = datetime.datetime(2019, 1, 2, 12, tzinfo=tz.UTC) - end = datetime.datetime(2019, 1, 2, 13, tzinfo=tz.UTC) + start = datetime.datetime(2019, 1, 2, 12, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 1, 2, 13, tzinfo=tz.tzutc()) point = dataframe.DataPoint( 'unit', 0, 0, {'g_one': 'one'}, {'m_two': 'two'}) usage = {'metric_x': [point]} @@ -251,8 +251,8 @@ class TestDataFrame(unittest.TestCase): ValueError, dataframe.DataFrame.from_dict, {'usage': None}) def test_repr(self): - start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.UTC) - end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.UTC) + start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.tzutc()) df = dataframe.DataFrame(start=start, end=end) points = [dataframe.DataPoint(**TestDataPoint.default_params) for _ in range(4)] @@ -262,8 +262,8 @@ class TestDataFrame(unittest.TestCase): self.assertEqual(str(df), "DataFrame(metrics=[metric_x,metric_y])") def test_iterpoints(self): - start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.UTC) - end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.UTC) + start = datetime.datetime(2019, 3, 4, 1, tzinfo=tz.tzutc()) + end = datetime.datetime(2019, 3, 4, 2, tzinfo=tz.tzutc()) df = dataframe.DataFrame(start=start, end=end) points = [dataframe.DataPoint(**TestDataPoint.default_params) for _ in range(4)] diff --git a/cloudkitty/tests/utils_tests/test_json.py b/cloudkitty/tests/utils_tests/test_json.py index e4c6119f..9c5dc8c0 100644 --- a/cloudkitty/tests/utils_tests/test_json.py +++ b/cloudkitty/tests/utils_tests/test_json.py @@ -28,6 +28,6 @@ class JSONEncoderTest(tests.TestCase): self.assertEqual(json.dumps(obj), '{"nb": 42.0}') def test_encode_datetime(self): - obj = {'date': datetime.datetime(2019, 1, 1, tzinfo=tz.UTC)} + obj = {'date': datetime.datetime(2019, 1, 1, tzinfo=tz.tzutc())} self.assertEqual(json.dumps(obj), '{"date": "2019-01-01T00:00:00+00:00"}') diff --git a/cloudkitty/tests/utils_tests/test_tz.py b/cloudkitty/tests/utils_tests/test_tz.py index 6e5e2312..01725f9e 100644 --- a/cloudkitty/tests/utils_tests/test_tz.py +++ b/cloudkitty/tests/utils_tests/test_tz.py @@ -31,7 +31,7 @@ class TestTZUtils(unittest.TestCase): def test_localized_now(self): self.assertEqual( - self.local_now.astimezone(tz.UTC).replace(tzinfo=None), + self.local_now.astimezone(tz.tzutc()).replace(tzinfo=None), self.naive_now) self.assertIsNotNone(self.local_now.tzinfo) @@ -63,15 +63,15 @@ class TestTZUtils(unittest.TestCase): def _test_add_substract_delta(self, obj, tzone): delta = datetime.timedelta(seconds=3600) - naive = obj.astimezone(tz.UTC).replace(tzinfo=None) + naive = obj.astimezone(tz.tzutc()).replace(tzinfo=None) self.assertEqual( tzutils.add_delta(obj, delta).astimezone(tzone), - (naive + delta).replace(tzinfo=tz.UTC).astimezone(tzone), + (naive + delta).replace(tzinfo=tz.tzutc()).astimezone(tzone), ) self.assertEqual( tzutils.substract_delta(obj, delta).astimezone(tzone), - (naive - delta).replace(tzinfo=tz.UTC).astimezone(tzone), + (naive - delta).replace(tzinfo=tz.tzutc()).astimezone(tzone), ) def test_add_substract_delta_summertime(self): @@ -118,13 +118,13 @@ class TestTZUtils(unittest.TestCase): self.assertEqual(tzutils.diff_seconds(two, one), 30) def test_diff_seconds_positive_arg_aware_objects(self): - one = datetime.datetime(2019, 1, 1, 1, 1, 30, tzinfo=tz.UTC) - two = datetime.datetime(2019, 1, 1, 1, 1, tzinfo=tz.UTC) + one = datetime.datetime(2019, 1, 1, 1, 1, 30, tzinfo=tz.tzutc()) + two = datetime.datetime(2019, 1, 1, 1, 1, tzinfo=tz.tzutc()) self.assertEqual(tzutils.diff_seconds(one, two), 30) def test_diff_seconds_negative_arg_aware_objects(self): - one = datetime.datetime(2019, 1, 1, 1, 1, 30, tzinfo=tz.UTC) - two = datetime.datetime(2019, 1, 1, 1, 1, tzinfo=tz.UTC) + one = datetime.datetime(2019, 1, 1, 1, 1, 30, tzinfo=tz.tzutc()) + two = datetime.datetime(2019, 1, 1, 1, 1, tzinfo=tz.tzutc()) self.assertEqual(tzutils.diff_seconds(two, one), 30) def test_diff_seconds_negative_arg_aware_objects_on_summer_change(self): @@ -136,7 +136,7 @@ class TestTZUtils(unittest.TestCase): def test_cloudkitty_dt_from_ts_as_utc(self): ts = 1569902400 - dt = datetime.datetime(2019, 10, 1, 4, tzinfo=tz.UTC) + dt = datetime.datetime(2019, 10, 1, 4, tzinfo=tz.tzutc()) self.assertEqual(dt, tzutils.dt_from_ts(ts, as_utc=True)) def test_cloudkitty_dt_from_ts_local_tz(self): diff --git a/cloudkitty/utils/tz.py b/cloudkitty/utils/tz.py index 54392280..f3cbd87f 100644 --- a/cloudkitty/utils/tz.py +++ b/cloudkitty/utils/tz.py @@ -47,9 +47,9 @@ def local_to_utc(dt, naive=False): # applied to a naive datetime object. In python3 however, the naive object # is considered as being in the system's time. if dt.tzinfo is None: - dt = dt.replace(tzinfo=tz.UTC) + dt = dt.replace(tzinfo=tz.tzutc()) - output = dt.astimezone(tz.UTC) + output = dt.astimezone(tz.tzutc()) if naive: output = output.replace(tzinfo=None) return output @@ -65,7 +65,7 @@ def utc_to_local(dt): :rtype: datetime.datetime """ if dt.tzinfo is None: - dt = dt.replace(tzinfo=tz.UTC) + dt = dt.replace(tzinfo=tz.tzutc()) return dt.astimezone(_LOCAL_TZ) @@ -81,7 +81,7 @@ def dt_from_iso(time_str, as_utc=False): :rtype: datetime.datetime """ return timeutils.parse_isotime(time_str).astimezone( - tz.UTC if as_utc else _LOCAL_TZ).replace(microsecond=0) + tz.tzutc() if as_utc else _LOCAL_TZ).replace(microsecond=0) def dt_from_ts(ts, as_utc=False): @@ -89,7 +89,8 @@ def dt_from_ts(ts, as_utc=False): Returns the object as being from the local timezone. """ - return datetime.datetime.fromtimestamp(ts, tz.UTC if as_utc else _LOCAL_TZ) + return datetime.datetime.fromtimestamp( + ts, tz.tzutc() if as_utc else _LOCAL_TZ) def add_delta(dt, delta): @@ -134,7 +135,7 @@ def get_month_start(dt=None, naive=False): if not dt: dt = localized_now() if not dt.tzinfo: - dt = dt.replace(tzinfo=tz.UTC).astimezone(_LOCAL_TZ) + dt = dt.replace(tzinfo=tz.tzutc()).astimezone(_LOCAL_TZ) if naive: dt = local_to_utc(dt, naive=True) return datetime.datetime(dt.year, dt.month, 1, tzinfo=dt.tzinfo) diff --git a/lower-constraints.txt b/lower-constraints.txt index 412a79d2..49dce307 100644 --- a/lower-constraints.txt +++ b/lower-constraints.txt @@ -21,6 +21,7 @@ oslo.middleware==3.27.0 # Apache-2.0 oslo.policy==0.5.0 # Apache-2.0 oslo.utils==3.5.0 # Apache-2.0 oslo.upgradecheck==0.1.1 # Apache-2.0 +python-dateutil==2.5.3 # BSD SQLAlchemy==1.0.10 # MIT six==1.9.0 # MIT stevedore==1.5.0 # Apache-2.0 diff --git a/releasenotes/notes/remove-dateutil-tz-utc-usage-1350c00be3fadde7.yaml b/releasenotes/notes/remove-dateutil-tz-utc-usage-1350c00be3fadde7.yaml new file mode 100644 index 00000000..96be7987 --- /dev/null +++ b/releasenotes/notes/remove-dateutil-tz-utc-usage-1350c00be3fadde7.yaml @@ -0,0 +1,5 @@ +--- +fixes: + - | + The use of ``tz.UTC`` from the ``dateutil`` package was removed, bringing + compatibility with the version available in RHEL and CentOS 8. diff --git a/requirements.txt b/requirements.txt index f103346b..ca8623a3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -23,6 +23,7 @@ oslo.middleware>=3.27.0 # Apache-2.0 oslo.policy>=0.5.0 # Apache-2.0 oslo.utils>=3.5.0 # Apache-2.0 oslo.upgradecheck>=0.1.1 # Apache-2.0 +python-dateutil>=2.5.3 # BSD SQLAlchemy>=1.0.10,!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8 # MIT six>=1.9.0 # MIT stevedore>=1.5.0 # Apache-2.0