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
This commit is contained in:
Eric Harney 2023-05-04 11:40:51 -04:00 committed by Takashi Kajinami
parent e9c18c7f94
commit 7afc7ae2ac
13 changed files with 46 additions and 37 deletions

View File

@ -22,13 +22,13 @@ from __future__ import annotations
from datetime import datetime from datetime import datetime
import random import random
from typing import Optional from typing import Optional
from zoneinfo import ZoneInfo
from eventlet import greenthread from eventlet import greenthread
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import excutils from oslo_utils import excutils
from oslo_utils import strutils from oslo_utils import strutils
from pytz import timezone
from cinder.backup import rpcapi as backup_rpcapi from cinder.backup import rpcapi as backup_rpcapi
from cinder.common import constants from cinder.common import constants
@ -301,7 +301,7 @@ class API(base.Base):
if (x['status'] == fields.BackupStatus.AVAILABLE and ( if (x['status'] == fields.BackupStatus.AVAILABLE and (
not snapshot or (snapshot and x['data_timestamp'] not snapshot or (snapshot and x['data_timestamp']
< snapshot['created_at']))) < 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: else:
QUOTAS.rollback(context, reservations) QUOTAS.rollback(context, reservations)
msg = _('No backups available to do an incremental backup.') msg = _('No backups available to do an incremental backup.')

View File

@ -13,11 +13,11 @@
# under the License. # under the License.
from typing import Optional from typing import Optional
from zoneinfo import ZoneInfo
from oslo_config import cfg from oslo_config import cfg
from oslo_log import log as logging from oslo_log import log as logging
from oslo_utils import timeutils from oslo_utils import timeutils
from pytz import timezone
from cinder import context from cinder import context
from cinder import objects from cinder import objects
@ -114,7 +114,7 @@ class ImageVolumeCache(object):
if isinstance(image_updated_at, str): if isinstance(image_updated_at, str):
image_updated_at = timeutils.parse_strtime(image_updated_at) image_updated_at = timeutils.parse_strtime(image_updated_at)
else: 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( cache_entry = self.db.image_volume_cache_create(
context, context,
@ -252,9 +252,9 @@ class ImageVolumeCache(object):
image_meta: dict) -> bool: image_meta: dict) -> bool:
"""Ensure that the cache entry image data is still valid.""" """Ensure that the cache entry image data is still valid."""
image_updated_utc = (image_meta['updated_at'] image_updated_utc = (image_meta['updated_at']
.astimezone(timezone('UTC'))) .astimezone(ZoneInfo('UTC')))
cache_updated_utc = (cache_entry['image_updated_at'] 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, ' LOG.debug('Image-volume cache entry image_update_at = %(entry_utc)s, '
'requested image updated_at = %(image_utc)s.', 'requested image updated_at = %(image_utc)s.',

View File

@ -17,10 +17,10 @@ import datetime
from http import HTTPStatus from http import HTTPStatus
from unittest import mock from unittest import mock
from urllib import parse as urllib from urllib import parse as urllib
from zoneinfo import ZoneInfo
import ddt import ddt
from oslo_config import cfg from oslo_config import cfg
import pytz
import webob import webob
from cinder.api import common from cinder.api import common
@ -269,7 +269,7 @@ class SnapshotApiTest(test.TestCase):
'status': fields.SnapshotStatus.AVAILABLE, 'status': fields.SnapshotStatus.AVAILABLE,
'size': 100, 'size': 100,
'created_at': datetime.datetime(2014, 1, 1, 0, 0, 0, 'created_at': datetime.datetime(2014, 1, 1, 0, 0, 0,
tzinfo=pytz.utc), tzinfo=ZoneInfo('UTC')),
'updated_at': None, 'updated_at': None,
'name': u'Updated Test Name', 'name': u'Updated Test Name',
'description': u'Default description', 'description': u'Default description',
@ -376,7 +376,7 @@ class SnapshotApiTest(test.TestCase):
'status': fields.SnapshotStatus.AVAILABLE, 'status': fields.SnapshotStatus.AVAILABLE,
'size': 100, 'size': 100,
'created_at': datetime.datetime(2018, 1, 14, 0, 0, 0, 'created_at': datetime.datetime(2018, 1, 14, 0, 0, 0,
tzinfo=pytz.utc), tzinfo=ZoneInfo('UTC')),
'updated_at': None, 'updated_at': None,
'name': u'test', 'name': u'test',
'description': u'test', 'description': u'test',

View File

@ -13,9 +13,9 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder.db.sqlalchemy import models from cinder.db.sqlalchemy import models
from cinder import exception from cinder import exception
@ -118,8 +118,9 @@ class TestBackup(test_objects.BaseObjectsTestCase):
self.assertTrue(admin_context.is_admin) self.assertTrue(admin_context.is_admin)
self.assertTrue(backup.deleted) self.assertTrue(backup.deleted)
self.assertEqual(fields.BackupStatus.DELETED, backup.status) self.assertEqual(fields.BackupStatus.DELETED, backup.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
backup.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
backup.deleted_at)
def test_obj_field_temp_volume_snapshot_id(self): def test_obj_field_temp_volume_snapshot_id(self):
backup = objects.Backup(context=self.context, backup = objects.Backup(context=self.context,

View File

@ -13,9 +13,9 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import exception from cinder import exception
from cinder import objects from cinder import objects
@ -98,8 +98,9 @@ class TestCGSnapshot(test_objects.BaseObjectsTestCase):
self.assertTrue(admin_context.is_admin) self.assertTrue(admin_context.is_admin)
self.assertTrue(cgsnapshot.deleted) self.assertTrue(cgsnapshot.deleted)
self.assertEqual('deleted', cgsnapshot.status) self.assertEqual('deleted', cgsnapshot.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
cgsnapshot.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
cgsnapshot.deleted_at)
@mock.patch('cinder.objects.consistencygroup.ConsistencyGroup.get_by_id') @mock.patch('cinder.objects.consistencygroup.ConsistencyGroup.get_by_id')
@mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot') @mock.patch('cinder.objects.snapshot.SnapshotList.get_all_for_cgsnapshot')

View File

@ -13,9 +13,9 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import exception from cinder import exception
from cinder import objects from cinder import objects
@ -194,8 +194,9 @@ class TestConsistencyGroup(test_objects.BaseObjectsTestCase):
self.assertTrue(consistencygroup.deleted) self.assertTrue(consistencygroup.deleted)
self.assertEqual(fields.ConsistencyGroupStatus.DELETED, self.assertEqual(fields.ConsistencyGroupStatus.DELETED,
consistencygroup.status) consistencygroup.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
consistencygroup.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
consistencygroup.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api.consistencygroup_get') @mock.patch('cinder.db.sqlalchemy.api.consistencygroup_get')
def test_refresh(self, consistencygroup_get): def test_refresh(self, consistencygroup_get):

View File

@ -13,9 +13,9 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import exception from cinder import exception
from cinder import objects from cinder import objects
@ -103,8 +103,9 @@ class TestGroupSnapshot(test_objects.BaseObjectsTestCase):
self.assertTrue(group_snapshot.deleted) self.assertTrue(group_snapshot.deleted)
self.assertEqual(fields.GroupSnapshotStatus.DELETED, self.assertEqual(fields.GroupSnapshotStatus.DELETED,
group_snapshot.status) group_snapshot.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
group_snapshot.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
group_snapshot.deleted_at)
@mock.patch('cinder.objects.group.Group.get_by_id') @mock.patch('cinder.objects.group.Group.get_by_id')
@mock.patch( @mock.patch(

View File

@ -11,9 +11,9 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder.db.sqlalchemy import models from cinder.db.sqlalchemy import models
from cinder import exception 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']) qos_fake_delete.assert_called_once_with(mock.ANY, fake_qos['id'])
self.assertTrue(qos_object.deleted) self.assertTrue(qos_object.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
qos_object.deleted_at) 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.sqlalchemy.api.qos_specs_delete')
@mock.patch('cinder.db.qos_specs_disassociate_all') @mock.patch('cinder.db.qos_specs_disassociate_all')

View File

@ -14,10 +14,10 @@
import datetime import datetime
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
import ddt import ddt
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import exception from cinder import exception
from cinder import objects from cinder import objects
@ -92,8 +92,9 @@ class TestService(test_objects.BaseObjectsTestCase):
service.destroy() service.destroy()
service_destroy.assert_called_once_with(elevated_ctx(), 123) service_destroy.assert_called_once_with(elevated_ctx(), 123)
self.assertTrue(service.deleted) self.assertTrue(service.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
service.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
service.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api.service_get') @mock.patch('cinder.db.sqlalchemy.api.service_get')
def test_refresh(self, service_get): def test_refresh(self, service_get):

View File

@ -14,10 +14,10 @@
import copy import copy
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
import ddt import ddt
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder.db.sqlalchemy import models from cinder.db.sqlalchemy import models
from cinder import exception from cinder import exception
@ -131,8 +131,9 @@ class TestSnapshot(test_objects.BaseObjectsTestCase):
self.assertTrue(admin_context.is_admin) self.assertTrue(admin_context.is_admin)
self.assertTrue(snapshot.deleted) self.assertTrue(snapshot.deleted)
self.assertEqual(fields.SnapshotStatus.DELETED, snapshot.status) self.assertEqual(fields.SnapshotStatus.DELETED, snapshot.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
snapshot.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
snapshot.deleted_at)
@mock.patch('cinder.db.snapshot_metadata_delete') @mock.patch('cinder.db.snapshot_metadata_delete')
def test_delete_metadata_key(self, snapshot_metadata_delete): def test_delete_metadata_key(self, snapshot_metadata_delete):

View File

@ -13,10 +13,10 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
import ddt import ddt
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import context from cinder import context
from cinder import exception from cinder import exception
@ -177,8 +177,9 @@ class TestVolume(test_objects.BaseObjectsTestCase):
self.assertTrue(admin_context.is_admin) self.assertTrue(admin_context.is_admin)
self.assertTrue(volume.deleted) self.assertTrue(volume.deleted)
self.assertEqual('deleted', volume.status) self.assertEqual('deleted', volume.status)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
volume.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
volume.deleted_at)
self.assertIsNone(volume.migration_status) self.assertIsNone(volume.migration_status)
def test_obj_fields(self): def test_obj_fields(self):

View File

@ -13,10 +13,10 @@
# under the License. # under the License.
from unittest import mock from unittest import mock
from zoneinfo import ZoneInfo
import ddt import ddt
from oslo_utils import timeutils from oslo_utils import timeutils
import pytz
from cinder import db from cinder import db
from cinder.db.sqlalchemy import models from cinder.db.sqlalchemy import models
@ -123,8 +123,9 @@ class TestVolumeType(test_objects.BaseObjectsTestCase):
admin_context = volume_type_destroy.call_args[0][0] admin_context = volume_type_destroy.call_args[0][0]
self.assertTrue(admin_context.is_admin) self.assertTrue(admin_context.is_admin)
self.assertTrue(volume_type.deleted) self.assertTrue(volume_type.deleted)
self.assertEqual(utcnow_mock.return_value.replace(tzinfo=pytz.UTC), self.assertEqual(
volume_type.deleted_at) utcnow_mock.return_value.replace(tzinfo=ZoneInfo('UTC')),
volume_type.deleted_at)
@mock.patch('cinder.db.sqlalchemy.api._volume_type_get_full') @mock.patch('cinder.db.sqlalchemy.api._volume_type_get_full')
def test_refresh(self, volume_type_get): def test_refresh(self, volume_type_get):

View File

@ -41,7 +41,6 @@ python-glanceclient>=3.2.2 # Apache-2.0
python-keystoneclient>=4.1.1 # Apache-2.0 python-keystoneclient>=4.1.1 # Apache-2.0
python-novaclient>=18.2.0 # Apache-2.0 python-novaclient>=18.2.0 # Apache-2.0
python-swiftclient>=3.10.1 # Apache-2.0 python-swiftclient>=3.10.1 # Apache-2.0
pytz>=2020.1 # MIT
requests>=2.25.1 # Apache-2.0 requests>=2.25.1 # Apache-2.0
Routes>=2.4.1 # MIT Routes>=2.4.1 # MIT
taskflow>=4.5.0 # Apache-2.0 taskflow>=4.5.0 # Apache-2.0
@ -64,3 +63,4 @@ cursive>=0.2.2 # Apache-2.0
zstd>=1.4.5.1 # BSD zstd>=1.4.5.1 # BSD
boto3>=1.18.49 # Apache-2.0 boto3>=1.18.49 # Apache-2.0
distro>=1.8.0 # Apache-2.0 distro>=1.8.0 # Apache-2.0
tzdata>=2022.4 # MIT