From 7afc7ae2acaac1485c37fa367eedab4becda02b7 Mon Sep 17 00:00:00 2001 From: Eric Harney Date: Thu, 4 May 2023 11:40:51 -0400 Subject: [PATCH] Remove pytz dependency Use built-in zoneinfo lib which was introduced in Python 3.9. Adds a requirement on tzdata to ensure that tzdata is installed if not provided by the system. See more details in https://review.opendev.org/c/openstack/requirements/+/875854 Change-Id: If4b711c45ca8a4ec3ec13623597739cc095c0352 --- cinder/backup/api.py | 4 ++-- cinder/image/cache.py | 8 ++++---- cinder/tests/unit/api/v2/test_snapshots.py | 6 +++--- cinder/tests/unit/objects/test_backup.py | 7 ++++--- cinder/tests/unit/objects/test_cgsnapshot.py | 7 ++++--- cinder/tests/unit/objects/test_consistencygroup.py | 7 ++++--- cinder/tests/unit/objects/test_group_snapshot.py | 7 ++++--- cinder/tests/unit/objects/test_qos.py | 7 ++++--- cinder/tests/unit/objects/test_service.py | 7 ++++--- cinder/tests/unit/objects/test_snapshot.py | 7 ++++--- cinder/tests/unit/objects/test_volume.py | 7 ++++--- cinder/tests/unit/objects/test_volume_type.py | 7 ++++--- requirements.txt | 2 +- 13 files changed, 46 insertions(+), 37 deletions(-) diff --git a/cinder/backup/api.py b/cinder/backup/api.py index ec312d75488..bcb4308d184 100644 --- a/cinder/backup/api.py +++ b/cinder/backup/api.py @@ -22,13 +22,13 @@ from __future__ import annotations from datetime import datetime import random from typing import Optional +from zoneinfo import ZoneInfo from eventlet import greenthread from oslo_config import cfg from oslo_log import log as logging from oslo_utils import excutils from oslo_utils import strutils -from pytz import timezone from cinder.backup import rpcapi as backup_rpcapi from cinder.common import constants @@ -301,7 +301,7 @@ class API(base.Base): if (x['status'] == fields.BackupStatus.AVAILABLE and ( not snapshot or (snapshot and x['data_timestamp'] < snapshot['created_at']))) - else datetime(1, 1, 1, 1, 1, 1, tzinfo=timezone('UTC'))) + else datetime(1, 1, 1, 1, 1, 1, tzinfo=ZoneInfo('UTC'))) else: QUOTAS.rollback(context, reservations) msg = _('No backups available to do an incremental backup.') diff --git a/cinder/image/cache.py b/cinder/image/cache.py index 6d30210a44a..4636b681c66 100644 --- a/cinder/image/cache.py +++ b/cinder/image/cache.py @@ -13,11 +13,11 @@ # under the License. from typing import Optional +from zoneinfo import ZoneInfo from oslo_config import cfg from oslo_log import log as logging from oslo_utils import timeutils -from pytz import timezone from cinder import context from cinder import objects @@ -114,7 +114,7 @@ class ImageVolumeCache(object): if isinstance(image_updated_at, str): image_updated_at = timeutils.parse_strtime(image_updated_at) else: - image_updated_at = image_updated_at.astimezone(timezone('UTC')) + image_updated_at = image_updated_at.astimezone(ZoneInfo('UTC')) cache_entry = self.db.image_volume_cache_create( context, @@ -252,9 +252,9 @@ class ImageVolumeCache(object): image_meta: dict) -> bool: """Ensure that the cache entry image data is still valid.""" image_updated_utc = (image_meta['updated_at'] - .astimezone(timezone('UTC'))) + .astimezone(ZoneInfo('UTC'))) cache_updated_utc = (cache_entry['image_updated_at'] - .replace(tzinfo=timezone('UTC'))) + .replace(tzinfo=ZoneInfo('UTC'))) LOG.debug('Image-volume cache entry image_update_at = %(entry_utc)s, ' 'requested image updated_at = %(image_utc)s.', diff --git a/cinder/tests/unit/api/v2/test_snapshots.py b/cinder/tests/unit/api/v2/test_snapshots.py index d85ae2d3322..85419d4cdd7 100644 --- a/cinder/tests/unit/api/v2/test_snapshots.py +++ b/cinder/tests/unit/api/v2/test_snapshots.py @@ -17,10 +17,10 @@ import datetime from http import HTTPStatus from unittest import mock from urllib import parse as urllib +from zoneinfo import ZoneInfo import ddt from oslo_config import cfg -import pytz import webob from cinder.api import common @@ -269,7 +269,7 @@ class SnapshotApiTest(test.TestCase): 'status': fields.SnapshotStatus.AVAILABLE, 'size': 100, 'created_at': datetime.datetime(2014, 1, 1, 0, 0, 0, - tzinfo=pytz.utc), + tzinfo=ZoneInfo('UTC')), 'updated_at': None, 'name': u'Updated Test Name', 'description': u'Default description', @@ -376,7 +376,7 @@ class SnapshotApiTest(test.TestCase): 'status': fields.SnapshotStatus.AVAILABLE, 'size': 100, 'created_at': datetime.datetime(2018, 1, 14, 0, 0, 0, - tzinfo=pytz.utc), + tzinfo=ZoneInfo('UTC')), 'updated_at': None, 'name': u'test', 'description': u'test', diff --git a/cinder/tests/unit/objects/test_backup.py b/cinder/tests/unit/objects/test_backup.py index 768affa55c3..8b9f7f4d349 100644 --- a/cinder/tests/unit/objects/test_backup.py +++ b/cinder/tests/unit/objects/test_backup.py @@ -13,9 +13,9 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo from oslo_utils import timeutils -import pytz from cinder.db.sqlalchemy import models from cinder import exception @@ -118,8 +118,9 @@ class TestBackup(test_objects.BaseObjectsTestCase): self.assertTrue(admin_context.is_admin) self.assertTrue(backup.deleted) self.assertEqual(fields.BackupStatus.DELETED, backup.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - backup.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + backup.deleted_at) def test_obj_field_temp_volume_snapshot_id(self): backup = objects.Backup(context=self.context, diff --git a/cinder/tests/unit/objects/test_cgsnapshot.py b/cinder/tests/unit/objects/test_cgsnapshot.py index cbcfc6b270d..d41d88f11d9 100644 --- a/cinder/tests/unit/objects/test_cgsnapshot.py +++ b/cinder/tests/unit/objects/test_cgsnapshot.py @@ -13,9 +13,9 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo from oslo_utils import timeutils -import pytz from cinder import exception from cinder import objects @@ -98,8 +98,9 @@ class TestCGSnapshot(test_objects.BaseObjectsTestCase): self.assertTrue(admin_context.is_admin) self.assertTrue(cgsnapshot.deleted) self.assertEqual('deleted', cgsnapshot.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - cgsnapshot.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + cgsnapshot.deleted_at) @mock.patch('cinder.objects.consistencygroup.ConsistencyGroup.get_by_id') @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot') diff --git a/cinder/tests/unit/objects/test_consistencygroup.py b/cinder/tests/unit/objects/test_consistencygroup.py index db43f6897b8..4440eaa8e27 100644 --- a/cinder/tests/unit/objects/test_consistencygroup.py +++ b/cinder/tests/unit/objects/test_consistencygroup.py @@ -13,9 +13,9 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo from oslo_utils import timeutils -import pytz from cinder import exception from cinder import objects @@ -194,8 +194,9 @@ class TestConsistencyGroup(test_objects.BaseObjectsTestCase): self.assertTrue(consistencygroup.deleted) self.assertEqual(fields.ConsistencyGroupStatus.DELETED, consistencygroup.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - consistencygroup.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + consistencygroup.deleted_at) @mock.patch('cinder.db.sqlalchemy.api.consistencygroup_get') def test_refresh(self, consistencygroup_get): diff --git a/cinder/tests/unit/objects/test_group_snapshot.py b/cinder/tests/unit/objects/test_group_snapshot.py index ec168e6ec44..a92b00f298b 100644 --- a/cinder/tests/unit/objects/test_group_snapshot.py +++ b/cinder/tests/unit/objects/test_group_snapshot.py @@ -13,9 +13,9 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo from oslo_utils import timeutils -import pytz from cinder import exception from cinder import objects @@ -103,8 +103,9 @@ class TestGroupSnapshot(test_objects.BaseObjectsTestCase): self.assertTrue(group_snapshot.deleted) self.assertEqual(fields.GroupSnapshotStatus.DELETED, group_snapshot.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - group_snapshot.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + group_snapshot.deleted_at) @mock.patch('cinder.objects.group.Group.get_by_id') @mock.patch( diff --git a/cinder/tests/unit/objects/test_qos.py b/cinder/tests/unit/objects/test_qos.py index ff39bd6747c..38817689579 100644 --- a/cinder/tests/unit/objects/test_qos.py +++ b/cinder/tests/unit/objects/test_qos.py @@ -11,9 +11,9 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo from oslo_utils import timeutils -import pytz from cinder.db.sqlalchemy import models from cinder import exception @@ -97,8 +97,9 @@ class TestQos(test_objects.BaseObjectsTestCase): qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id']) self.assertTrue(qos_object.deleted) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - qos_object.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + qos_object.deleted_at) @mock.patch('cinder.db.sqlalchemy.api.qos_specs_delete') @mock.patch('cinder.db.qos_specs_disassociate_all') diff --git a/cinder/tests/unit/objects/test_service.py b/cinder/tests/unit/objects/test_service.py index a467d01bc9f..91e5b631dbb 100644 --- a/cinder/tests/unit/objects/test_service.py +++ b/cinder/tests/unit/objects/test_service.py @@ -14,10 +14,10 @@ import datetime from unittest import mock +from zoneinfo import ZoneInfo import ddt from oslo_utils import timeutils -import pytz from cinder import exception from cinder import objects @@ -92,8 +92,9 @@ class TestService(test_objects.BaseObjectsTestCase): service.destroy() service_destroy.assert_called_once_with(elevated_ctx(), 123) self.assertTrue(service.deleted) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - service.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + service.deleted_at) @mock.patch('cinder.db.sqlalchemy.api.service_get') def test_refresh(self, service_get): diff --git a/cinder/tests/unit/objects/test_snapshot.py b/cinder/tests/unit/objects/test_snapshot.py index 032786d1e74..9d13e10996d 100644 --- a/cinder/tests/unit/objects/test_snapshot.py +++ b/cinder/tests/unit/objects/test_snapshot.py @@ -14,10 +14,10 @@ import copy from unittest import mock +from zoneinfo import ZoneInfo import ddt from oslo_utils import timeutils -import pytz from cinder.db.sqlalchemy import models from cinder import exception @@ -131,8 +131,9 @@ class TestSnapshot(test_objects.BaseObjectsTestCase): self.assertTrue(admin_context.is_admin) self.assertTrue(snapshot.deleted) self.assertEqual(fields.SnapshotStatus.DELETED, snapshot.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - snapshot.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + snapshot.deleted_at) @mock.patch('cinder.db.snapshot_metadata_delete') def test_delete_metadata_key(self, snapshot_metadata_delete): diff --git a/cinder/tests/unit/objects/test_volume.py b/cinder/tests/unit/objects/test_volume.py index d289f82b2ba..85daf384af8 100644 --- a/cinder/tests/unit/objects/test_volume.py +++ b/cinder/tests/unit/objects/test_volume.py @@ -13,10 +13,10 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo import ddt from oslo_utils import timeutils -import pytz from cinder import context from cinder import exception @@ -177,8 +177,9 @@ class TestVolume(test_objects.BaseObjectsTestCase): self.assertTrue(admin_context.is_admin) self.assertTrue(volume.deleted) self.assertEqual('deleted', volume.status) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - volume.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + volume.deleted_at) self.assertIsNone(volume.migration_status) def test_obj_fields(self): diff --git a/cinder/tests/unit/objects/test_volume_type.py b/cinder/tests/unit/objects/test_volume_type.py index 042859436a6..d40d013b354 100644 --- a/cinder/tests/unit/objects/test_volume_type.py +++ b/cinder/tests/unit/objects/test_volume_type.py @@ -13,10 +13,10 @@ # under the License. from unittest import mock +from zoneinfo import ZoneInfo import ddt from oslo_utils import timeutils -import pytz from cinder import db from cinder.db.sqlalchemy import models @@ -123,8 +123,9 @@ class TestVolumeType(test_objects.BaseObjectsTestCase): admin_context = volume_type_destroy.call_args[0][0] self.assertTrue(admin_context.is_admin) self.assertTrue(volume_type.deleted) - self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), - volume_type.deleted_at) + self.assertEqual( + utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')), + volume_type.deleted_at) @mock.patch('cinder.db.sqlalchemy.api._volume_type_get_full') def test_refresh(self, volume_type_get): diff --git a/requirements.txt b/requirements.txt index 4bc51d9a505..7ad69029aad 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,6 @@ python-glanceclient>=3.2.2 # Apache-2.0 python-keystoneclient>=4.1.1 # Apache-2.0 python-novaclient>=18.2.0 # Apache-2.0 python-swiftclient>=3.10.1 # Apache-2.0 -pytz>=2020.1 # MIT requests>=2.25.1 # Apache-2.0 Routes>=2.4.1 # MIT taskflow>=4.5.0 # Apache-2.0 @@ -64,3 +63,4 @@ cursive>=0.2.2 # Apache-2.0 zstd>=1.4.5.1 # BSD boto3>=1.18.49 # Apache-2.0 distro>=1.8.0 # Apache-2.0 +tzdata>=2022.4 # MIT