From 220144e4964dd132de35da5005093126b4932929 Mon Sep 17 00:00:00 2001 From: Muhammad Umar Khan Date: Thu, 31 Oct 2024 18:55:04 +0500 Subject: [PATCH] feat: add timezones constants --- .../rest_api/v1/views/tests/test_home.py | 4 ++-- .../rest_api/v2/views/tests/test_home.py | 4 ++-- .../contentstore/tests/test_courseware_index.py | 2 +- lms/djangoapps/mobile_api/users/tests.py | 12 ++++++------ lms/djangoapps/mobile_api/users/views.py | 4 ++-- .../verify_student/tests/test_services.py | 13 +++++++------ openedx/core/djangoapps/user_api/preferences/api.py | 9 ++++----- .../user_api/preferences/tests/test_api.py | 7 ++++--- .../core/djangoapps/user_api/tests/test_views.py | 4 ++-- openedx/core/lib/time_zone_utils.py | 5 +++-- 10 files changed, 33 insertions(+), 31 deletions(-) diff --git a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py index a4a6909c5dcb..abd9ea18119f 100644 --- a/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py +++ b/cms/djangoapps/contentstore/rest_api/v1/views/tests/test_home.py @@ -2,7 +2,6 @@ Unit tests for home page view. """ import ddt -import pytz from collections import OrderedDict from datetime import datetime, timedelta from django.conf import settings @@ -12,6 +11,7 @@ override_waffle_switch, ) from rest_framework import status +from zoneinfo import ZoneInfo from cms.djangoapps.contentstore.tests.utils import CourseTestCase from cms.djangoapps.contentstore.tests.test_libraries import LibraryTestCase @@ -193,7 +193,7 @@ def test_filter_and_ordering_courses( display_name="Course (Demo)", id=archived_course_key, org=archived_course_key.org, - end=(datetime.now() - timedelta(days=365)).replace(tzinfo=pytz.UTC), + end=(datetime.now() - timedelta(days=365)).replace(tzinfo=ZoneInfo("UTC")), ) active_course_key = self.store.make_course_key("sample-org", "sample-number", "sample-run") CourseOverviewFactory.create( diff --git a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_home.py b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_home.py index 6904e05ae287..eaad213a8137 100644 --- a/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_home.py +++ b/cms/djangoapps/contentstore/rest_api/v2/views/tests/test_home.py @@ -6,12 +6,12 @@ from unittest.mock import patch import ddt -from zoneinfo import ZoneInfo from django.conf import settings from django.test import override_settings from django.urls import reverse from edx_toggles.toggles.testutils import override_waffle_switch from rest_framework import status +from zoneinfo import ZoneInfo from cms.djangoapps.contentstore.tests.utils import CourseTestCase from cms.djangoapps.contentstore.utils import reverse_course_url @@ -303,7 +303,7 @@ def test_filter_and_ordering_courses( display_name="Course (Demo)", id=archived_course_key, org=archived_course_key.org, - end=(datetime.now() - timedelta(days=365)).replace(tzinfo=pytz.UTC), + end=(datetime.now() - timedelta(days=365)).replace(tzinfo=ZoneInfo("UTC")), ) active_course_key = self.store.make_course_key("foo-org", "foo-number", "foo-run") CourseOverviewFactory.create( diff --git a/cms/djangoapps/contentstore/tests/test_courseware_index.py b/cms/djangoapps/contentstore/tests/test_courseware_index.py index e62fd8b62cd9..20ce436356ed 100644 --- a/cms/djangoapps/contentstore/tests/test_courseware_index.py +++ b/cms/djangoapps/contentstore/tests/test_courseware_index.py @@ -505,7 +505,7 @@ def test_delete_course_from_search_index_after_course_deletion(self): self._test_delete_course_from_search_index_after_course_deletion(self.store) def test_empty_course(self): - empty_course = CourseFactory.create(modulestore=self.store, start=datetime(2015, 3, 1, tzinfo=UTC)) + empty_course = CourseFactory.create(modulestore=self.store, start=datetime(2015, 3, 1, tzinfo=ZoneInfo("UTC"))) added_to_index = CoursewareSearchIndexer.do_course_reindex(self.store, empty_course.id) assert added_to_index == 0 diff --git a/lms/djangoapps/mobile_api/users/tests.py b/lms/djangoapps/mobile_api/users/tests.py index 63f31673e521..e5df4f4412d0 100644 --- a/lms/djangoapps/mobile_api/users/tests.py +++ b/lms/djangoapps/mobile_api/users/tests.py @@ -108,8 +108,8 @@ class TestUserEnrollmentApi(UrlResetMixin, MobileAPITestCase, MobileAuthUserTest ALLOW_ACCESS_TO_UNRELEASED_COURSE = True ALLOW_ACCESS_TO_MILESTONE_COURSE = True ALLOW_ACCESS_TO_NON_VISIBLE_COURSE = True - NEXT_WEEK = datetime.datetime.now(ZoneInfo("UTC")) + datetime.timedelta(days=7) - LAST_WEEK = datetime.datetime.now(ZoneInfo("UTC")) - datetime.timedelta(days=7) + NEXT_WEEK = datetime.datetime.now(ZoneInfo('UTC')) + datetime.timedelta(days=7) + LAST_WEEK = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=7) THREE_YEARS_AGO = now() - datetime.timedelta(days=(365 * 3)) ADVERTISED_START = "Spring 2016" ENABLED_SIGNALS = ['course_published'] @@ -1438,7 +1438,7 @@ def test_user_have_active_and_inactive_enrollments_and_no_completions(self) -> N old_course = CourseFactory.create(org="edx", mobile_available=True) self.enroll(old_course.id) old_enrollment = CourseEnrollment.objects.filter(user=self.user, course=old_course.course_id).first() - old_enrollment.created = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=31) + old_enrollment.created = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=31) old_enrollment.save() response = self.api_response(api_version=API_V1) @@ -1466,7 +1466,7 @@ def test_different_enrollment_dates(self, enrolled_days_ago: int, recently_activ course = CourseFactory.create(org="edx", mobile_available=True, run='1001') self.enroll(course.id) enrollment = CourseEnrollment.objects.filter(user=self.user, course=course.course_id).first() - enrollment.created = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=enrolled_days_ago) + enrollment.created = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=enrolled_days_ago) enrollment.save() response = self.api_response(api_version=API_V1) @@ -1500,7 +1500,7 @@ def test_different_completion_dates(self, completed_days_ago: int, recently_acti self.enroll(course.id) enrollment = CourseEnrollment.objects.filter(user=self.user, course=course.course_id).first() # make enrollment older 30 days ago - enrollment.created = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=50) + enrollment.created = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=50) enrollment.save() completion = BlockCompletion.objects.create( user=self.user, @@ -1509,7 +1509,7 @@ def test_different_completion_dates(self, completed_days_ago: int, recently_acti block_key=section.location, completion=0.5, ) - completion.created = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=completed_days_ago) + completion.created = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=completed_days_ago) completion.save() response = self.api_response(api_version=API_V1) diff --git a/lms/djangoapps/mobile_api/users/views.py b/lms/djangoapps/mobile_api/users/views.py index c86f3add9d36..ae487fb086e6 100644 --- a/lms/djangoapps/mobile_api/users/views.py +++ b/lms/djangoapps/mobile_api/users/views.py @@ -8,7 +8,6 @@ from functools import cached_property from typing import Dict, List, Optional, Set -import pytz from completion.exceptions import UnavailableCompletionData from completion.models import BlockCompletion from completion.utilities import get_key_to_last_completed_block @@ -25,6 +24,7 @@ from rest_framework.decorators import api_view from rest_framework.permissions import SAFE_METHODS from rest_framework.response import Response +from zoneinfo import ZoneInfo from xblock.fields import Scope from xblock.runtime import KeyValueStore from edx_rest_framework_extensions.paginators import DefaultPagination @@ -597,7 +597,7 @@ def get(self, request, *args, **kwargs) -> Response: """ Gets user's enrollments status. """ - active_status_date = datetime.datetime.now(pytz.UTC) - datetime.timedelta(days=30) + active_status_date = datetime.datetime.now(ZoneInfo('UTC')) - datetime.timedelta(days=30) username = kwargs.get('username') course_ids_where_user_has_completions = self._get_course_ids_where_user_has_completions( username, diff --git a/lms/djangoapps/verify_student/tests/test_services.py b/lms/djangoapps/verify_student/tests/test_services.py index 5b9201ca9a5c..1286ec62343d 100644 --- a/lms/djangoapps/verify_student/tests/test_services.py +++ b/lms/djangoapps/verify_student/tests/test_services.py @@ -257,7 +257,7 @@ def test_approved_software_secure_verification(self): SoftwareSecurePhotoVerification.objects.create(user=self.user, status='approved') status = IDVerificationService.user_status(self.user) expected_status = {'status': 'approved', 'error': '', 'should_display': True, 'verification_expiry': '', - 'status_date': datetime.now(ZoneInfo("UTC"))} + 'status_date': datetime.now(ZoneInfo('UTC'))} self.assertDictEqual(status, expected_status) def test_denied_software_secure_verification(self): @@ -280,7 +280,7 @@ def test_approved_verification_attempt_verification(self): VerificationAttempt.objects.create(user=self.user, status='approved') status = IDVerificationService.user_status(self.user) expected_status = {'status': 'approved', 'error': '', 'should_display': True, 'verification_expiry': '', - 'status_date': datetime.now(ZoneInfo("UTC"))} + 'status_date': datetime.now(ZoneInfo('UTC'))} self.assertDictEqual(status, expected_status) def test_denied_verification_attempt_verification(self): @@ -303,7 +303,7 @@ def test_approved_sso_verification(self): SSOVerification.objects.create(user=self.user, status='approved') status = IDVerificationService.user_status(self.user) expected_status = {'status': 'approved', 'error': '', 'should_display': False, 'verification_expiry': '', - 'status_date': datetime.now(ZoneInfo("UTC"))} + 'status_date': datetime.now(ZoneInfo('UTC'))} self.assertDictEqual(status, expected_status) def test_denied_sso_verification(self): @@ -324,7 +324,7 @@ def test_manual_verification(self): ManualVerification.objects.create(user=self.user, status='approved') status = IDVerificationService.user_status(self.user) expected_status = {'status': 'approved', 'error': '', 'should_display': False, 'verification_expiry': '', - 'status_date': datetime.now(ZoneInfo("UTC"))} + 'status_date': datetime.now(ZoneInfo('UTC'))} self.assertDictEqual(status, expected_status) @ddt.idata(itertools.product( @@ -335,13 +335,14 @@ def test_expiring_software_secure_verification(self, value): verification_model, new_status = value with freeze_time('2015-07-11') as frozen_datetime: # create approved photo verification for the user - + verification_model.objects.create(user=self.user, status='approved') + expiring_datetime = datetime.now(ZoneInfo('UTC')) frozen_datetime.move_to('2015-07-14') # create another according to status passed in. verification_model.objects.create(user=self.user, status=new_status) status_date = expiring_datetime if new_status == 'approved': - status_date = datetime.now(ZoneInfo("UTC")) + status_date = datetime.now(ZoneInfo('UTC')) expected_status = {'status': 'approved', 'error': '', 'should_display': True, 'verification_expiry': '', 'status_date': status_date} status = IDVerificationService.user_status(self.user) diff --git a/openedx/core/djangoapps/user_api/preferences/api.py b/openedx/core/djangoapps/user_api/preferences/api.py index 8dbe37ab693c..e0a6797ebe25 100644 --- a/openedx/core/djangoapps/user_api/preferences/api.py +++ b/openedx/core/djangoapps/user_api/preferences/api.py @@ -11,8 +11,7 @@ from django.utils.translation import gettext as _ from django.utils.translation import gettext_noop from django_countries import countries -from zoneinfo import available_timezones -from pytz import country_timezones +from pytz import common_timezones, common_timezones_set, country_timezones from openedx.core.lib.time_zone_utils import get_display_time_zone from common.djangoapps.student.models import User, UserProfile @@ -430,7 +429,7 @@ def validate_user_preference_serializer(serializer, preference_key, preference_v "user_message": user_message, } }) - if preference_key == "time_zone" and preference_value not in available_timezones(): + if preference_key == "time_zone" and preference_value not in common_timezones_set: developer_message = gettext_noop("Value '{preference_value}' not valid for preference '{preference_key}': Not in timezone set.") # pylint: disable=line-too-long user_message = gettext_noop("Value '{preference_value}' is not a valid time zone selection.") raise PreferenceValidationError({ @@ -465,14 +464,14 @@ def get_country_time_zones(country_code=None): country_code (str): ISO 3166-1 Alpha-2 country code """ if country_code is None or country_code.upper() not in set(countries.alt_codes): - return _get_sorted_time_zone_list(available_timezones()) + return _get_sorted_time_zone_list(common_timezones) # We can still get a failure here because there are some countries that are # valid, but have no defined timezones in the pytz package (e.g. BV, HM) try: return _get_sorted_time_zone_list(country_timezones(country_code)) except KeyError: - return _get_sorted_time_zone_list(available_timezones()) + return _get_sorted_time_zone_list(common_timezones) def _get_sorted_time_zone_list(time_zone_list): diff --git a/openedx/core/djangoapps/user_api/preferences/tests/test_api.py b/openedx/core/djangoapps/user_api/preferences/tests/test_api.py index 67ea7f79e062..a069149c117e 100644 --- a/openedx/core/djangoapps/user_api/preferences/tests/test_api.py +++ b/openedx/core/djangoapps/user_api/preferences/tests/test_api.py @@ -11,7 +11,8 @@ from django.contrib.auth.models import User # lint-amnesty, pylint: disable=imported-auth-user from django.test.utils import override_settings from django.urls import reverse -from zoneinfo import ZoneInfo, available_timezones +from pytz import common_timezones +from zoneinfo import ZoneInfo from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms from openedx.core.lib.time_zone_utils import get_display_time_zone @@ -401,8 +402,8 @@ class CountryTimeZoneTest(CacheIsolationTestCase): """ @ddt.data(('ES', ['Africa/Ceuta', 'Atlantic/Canary', 'Europe/Madrid']), - (None, available_timezones()), - ('AA', available_timezones())) + (None, common_timezones), + ('AA', common_timezones)) @ddt.unpack def test_get_country_time_zones(self, country_code, expected_time_zones): """ diff --git a/openedx/core/djangoapps/user_api/tests/test_views.py b/openedx/core/djangoapps/user_api/tests/test_views.py index 4701eb87394e..75740cf5d2b6 100644 --- a/openedx/core/djangoapps/user_api/tests/test_views.py +++ b/openedx/core/djangoapps/user_api/tests/test_views.py @@ -5,7 +5,7 @@ from django.test.utils import override_settings from django.urls import reverse from opaque_keys.edx.keys import CourseKey -from zoneinfo import available_timezones +from pytz import common_timezones_set from openedx.core.djangoapps.django_comment_common import models from openedx.core.djangolib.testing.utils import CacheIsolationTestCase, skip_unless_lms @@ -631,7 +631,7 @@ def test_methods_not_allowed(self, country_uri): def _assert_time_zone_is_valid(self, time_zone_info): """ Asserts that the time zone is a valid pytz time zone """ time_zone_name = time_zone_info['time_zone'] - assert time_zone_name in available_timezones() + assert time_zone_name in common_timezones_set assert time_zone_info['description'] == get_display_time_zone(time_zone_name) # The time zones count may need to change each time we upgrade pytz diff --git a/openedx/core/lib/time_zone_utils.py b/openedx/core/lib/time_zone_utils.py index 01be5ca85fef..4c6e6645d87e 100644 --- a/openedx/core/lib/time_zone_utils.py +++ b/openedx/core/lib/time_zone_utils.py @@ -4,7 +4,8 @@ from datetime import datetime -from zoneinfo import ZoneInfo, available_timezones +from pytz import common_timezones +from zoneinfo import ZoneInfo def _format_time_zone_string(time_zone, date_time, format_string): @@ -49,6 +50,6 @@ def get_display_time_zone(time_zone_name): TIME_ZONE_CHOICES = sorted( - [(tz, get_display_time_zone(tz)) for tz in available_timezones()], + [(tz, get_display_time_zone(tz)) for tz in common_timezones], key=lambda tz_tuple: tz_tuple[1] )