diff --git a/horizon/middleware/base.py b/horizon/middleware/base.py index d5a806fecc..33f5f6b278 100644 --- a/horizon/middleware/base.py +++ b/horizon/middleware/base.py @@ -23,8 +23,6 @@ import datetime import json import logging -import pytz - from django.conf import settings from django.contrib.auth import REDIRECT_FIELD_NAME from django.contrib.auth.views import redirect_to_login @@ -74,7 +72,7 @@ class HorizonMiddleware(object): if settings.SESSION_REFRESH: timeout = settings.SESSION_TIMEOUT token_life = request.user.token.expires - datetime.datetime.now( - pytz.utc) + datetime.timezone.utc) session_time = min(timeout, int(token_life.total_seconds())) request.session.set_expiry(session_time) diff --git a/horizon/test/unit/middleware/test_base.py b/horizon/test/unit/middleware/test_base.py index b1425258c6..fd02634180 100644 --- a/horizon/test/unit/middleware/test_base.py +++ b/horizon/test/unit/middleware/test_base.py @@ -16,8 +16,6 @@ import datetime from unittest import mock -import pytz - from django.conf import settings from django.http import HttpResponseRedirect from django import test as django_test @@ -95,7 +93,7 @@ class MiddlewareTests(django_test.TestCase): request = self.factory.get(url) - now = datetime.datetime.now(pytz.utc) + now = datetime.datetime.now(datetime.timezone.utc) token_expiry = now + datetime.timedelta(seconds=1800) request.user.token = mock.Mock(expires=token_expiry) session_expiry_before = now + datetime.timedelta(seconds=300) @@ -117,7 +115,7 @@ class MiddlewareTests(django_test.TestCase): request = self.factory.get(url) - now = datetime.datetime.now(pytz.utc) + now = datetime.datetime.now(datetime.timezone.utc) token_expiry = now + datetime.timedelta(seconds=10) request.user.token = mock.Mock(expires=token_expiry) @@ -139,7 +137,7 @@ class MiddlewareTests(django_test.TestCase): request = self.factory.get(url) - now = datetime.datetime.now(pytz.utc) + now = datetime.datetime.now(datetime.timezone.utc) token_expiry = now + datetime.timedelta(seconds=1800) request.user.token = mock.Mock(expires=token_expiry) session_expiry_before = now + datetime.timedelta(seconds=300) diff --git a/openstack_auth/backend.py b/openstack_auth/backend.py index febacec2a3..d3daf4c17d 100644 --- a/openstack_auth/backend.py +++ b/openstack_auth/backend.py @@ -16,8 +16,6 @@ import datetime import logging -import pytz - from django.conf import settings from django.utils.module_loading import import_string from django.utils.translation import gettext_lazy as _ @@ -210,7 +208,8 @@ class KeystoneBackend(object): request.user = user timeout = settings.SESSION_TIMEOUT - token_life = user.token.expires - datetime.datetime.now(pytz.utc) + token_life = (user.token.expires - + datetime.datetime.now(datetime.timezone.utc)) session_time = min(timeout, int(token_life.total_seconds())) request.session.set_expiry(session_time) diff --git a/openstack_dashboard/api/rest/config.py b/openstack_dashboard/api/rest/config.py index 175d83f143..f4a182458a 100644 --- a/openstack_dashboard/api/rest/config.py +++ b/openstack_dashboard/api/rest/config.py @@ -14,12 +14,12 @@ # limitations under the License. from datetime import datetime +import zoneinfo from django.conf import settings from django.http import JsonResponse import django.template as django_template from django.views import generic -import pytz from openstack_dashboard import api from openstack_dashboard.api.rest import urls @@ -92,6 +92,6 @@ class Timezones(generic.View): @rest_utils.ajax() def get(self, request): - zones = {tz: datetime.now(pytz.timezone(tz)).strftime('%z') - for tz in pytz.common_timezones} + zones = {tz: datetime.now(zoneinfo.ZoneInfo(tz)).strftime('%z') + for tz in zoneinfo.available_timezones()} return JsonResponse({'timezone_dict': zones}) diff --git a/openstack_dashboard/dashboards/settings/user/forms.py b/openstack_dashboard/dashboards/settings/user/forms.py index 4997cc8002..1c1f58dfaa 100644 --- a/openstack_dashboard/dashboards/settings/user/forms.py +++ b/openstack_dashboard/dashboards/settings/user/forms.py @@ -14,6 +14,7 @@ from datetime import datetime import string +import zoneinfo import babel import babel.dates @@ -22,7 +23,6 @@ from django import shortcuts from django.utils import encoding from django.utils import translation from django.utils.translation import gettext_lazy as _ -import pytz from horizon import forms from horizon import messages @@ -42,10 +42,9 @@ class UserSettingsForm(forms.SelfHandlingForm): @staticmethod def _sorted_zones(): - today = datetime.today() - d = datetime(today.year, today.month, today.day) - zones = [(tz, pytz.timezone(tz).localize(d).strftime('%z')) - for tz in pytz.common_timezones] + zones = [(tz, datetime.now(zoneinfo.ZoneInfo(tz)).strftime('%z')) + for tz in zoneinfo.available_timezones() + if tz not in ('localtime', 'Factory')] zones.sort(key=lambda zone: int(zone[1])) return zones @@ -109,7 +108,7 @@ class UserSettingsForm(forms.SelfHandlingForm): response = functions.save_config_value( request, response, 'django_timezone', - pytz.timezone(data['timezone']).zone) + zoneinfo.ZoneInfo(data['timezone']).key) response = functions.save_config_value( request, response, 'API_RESULT_PAGE_SIZE', data['pagesize']) diff --git a/releasenotes/notes/remove-py38-6914ddb9fdf4cacd.yaml b/releasenotes/notes/remove-py38-6914ddb9fdf4cacd.yaml new file mode 100644 index 0000000000..53c00f3de2 --- /dev/null +++ b/releasenotes/notes/remove-py38-6914ddb9fdf4cacd.yaml @@ -0,0 +1,5 @@ +--- +upgrade: + - | + Python 3.8 support has been removed. Now the minimum supported python + version is 3.9. diff --git a/requirements.txt b/requirements.txt index 9eed09a458..048ba31ee3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -29,10 +29,10 @@ python-keystoneclient>=3.22.0 # Apache-2.0 python-neutronclient>=8.1.0 # Apache-2.0 python-novaclient>=9.1.0 # Apache-2.0 python-swiftclient>=3.2.0 # Apache-2.0 -pytz>=2013.6 # MIT PyYAML>=6.0 # MIT requests>=2.25.1 # Apache-2.0 semantic-version>=2.3.1 # BSD +tzdata>=2022.4 XStatic>=1.0.3 # MIT License XStatic-Angular>=1.8.2.2 # MIT License XStatic-Angular-Bootstrap>=2.2.0.0 # MIT License diff --git a/setup.cfg b/setup.cfg index 76ead952f3..fb3910c968 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,7 +6,7 @@ description_file = author = OpenStack author_email = openstack-discuss@lists.openstack.org home_page = https://docs.openstack.org/horizon/latest/ -python_requires = >=3.8 +python_requires = >=3.9 classifier = Development Status :: 5 - Production/Stable Environment :: OpenStack @@ -20,8 +20,9 @@ classifier = Programming Language :: Python Programming Language :: Python :: 3 :: Only Programming Language :: Python :: 3 - Programming Language :: Python :: 3.8 Programming Language :: Python :: 3.9 + Programming Language :: Python :: 3.10 + Programming Language :: Python :: 3.11 Topic :: Internet :: WWW/HTTP [global]