Skip to content

Commit 49eeb4d

Browse files
ttak-apphelixfeanil
authored andcommitted
chore: use zoneinfo instead of pytz
1 parent 7f1f876 commit 49eeb4d

29 files changed

Lines changed: 135 additions & 117 deletions

xmodule/assetstore/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@
77
from datetime import datetime
88

99
import dateutil.parser
10-
import pytz
1110
from lxml import etree
1211
from opaque_keys.edx.keys import AssetKey, CourseKey
12+
from zoneinfo import ZoneInfo
1313

1414

1515
class AssetMetadata:
@@ -80,7 +80,7 @@ def __init__(self, asset_id,
8080
self.thumbnail = thumbnail
8181
self.curr_version = curr_version
8282
self.prev_version = prev_version
83-
now = datetime.now(pytz.utc)
83+
now = datetime.now(ZoneInfo("UTC"))
8484
self.edited_by = edited_by
8585
self.edited_by_email = edited_by_email
8686
self.edited_on = edited_on or now

xmodule/capa/capa_problem.py

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626

2727
from django.conf import settings
2828
from lxml import etree
29-
from pytz import UTC
3029

3130
from openedx.core.djangolib.markup import HTML, Text
3231
from openedx.core.lib.safe_lxml.xmlparser import XML
@@ -35,6 +34,7 @@
3534
from xmodule.capa.safe_exec import safe_exec
3635
from xmodule.capa.util import contextualize_text, convert_files_to_filenames, get_course_id_from_capa_block
3736
from xmodule.stringify import stringify_children
37+
from zoneinfo import ZoneInfo
3838

3939
# extra things displayed after "show answers" is pressed
4040
solution_tags = ["solution"]
@@ -437,7 +437,10 @@ def get_recentmost_queuetime(self):
437437
if self.correct_map.is_queued(answer_id)
438438
]
439439
queuetimes = [
440-
datetime.strptime(qt_str, xqueue_interface.DATEFORMAT).replace(tzinfo=UTC) for qt_str in queuetime_strs
440+
datetime.strptime(qt_str, xqueue_interface.DATEFORMAT).replace(
441+
tzinfo=ZoneInfo("UTC")
442+
)
443+
for qt_str in queuetime_strs
441444
]
442445

443446
return max(queuetimes)

xmodule/capa/responsetypes.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
from lxml import etree
3434
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
3535
from pyparsing import ParseException
36-
from pytz import UTC
3736
from shapely.geometry import MultiPoint, Point
3837
from six.moves import map, range, zip
3938
from symmath import symmath_check
@@ -42,6 +41,7 @@
4241
from openedx.core.lib.grade_utils import round_away_from_zero
4342
from xmodule.capa.safe_exec import safe_exec
4443
from xmodule.capa.xqueue_interface import DATEFORMAT, make_hashkey, make_xheader
44+
from zoneinfo import ZoneInfo
4545

4646
from . import correctmap
4747
from .registry import TagRegistry
@@ -2653,7 +2653,7 @@ def get_score(self, student_answers): # pylint: disable=too-many-locals
26532653
# ------------------------------------------------------------
26542654

26552655
qinterface = self.capa_system.xqueue.interface
2656-
qtime = datetime.strftime(datetime.now(UTC), DATEFORMAT)
2656+
qtime = datetime.strftime(datetime.now(ZoneInfo("UTC")), DATEFORMAT)
26572657

26582658
anonymous_student_id = self.capa_system.anonymous_student_id
26592659

xmodule/capa/tests/test_responsetypes.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@
1717
import pytest
1818
import random2 as random
1919
import requests
20-
from pytz import UTC
2120

2221
from xmodule.capa.correctmap import CorrectMap
2322
from xmodule.capa.responsetypes import (
@@ -49,6 +48,7 @@
4948
from xmodule.capa.tests.test_util import UseUnsafeCodejail
5049
from xmodule.capa.util import convert_files_to_filenames
5150
from xmodule.capa.xqueue_interface import DATEFORMAT
51+
from zoneinfo import ZoneInfo
5252

5353

5454
class ResponseTest(unittest.TestCase):
@@ -999,7 +999,7 @@ def test_is_queued(self):
999999
# Now we queue the LCP
10001000
cmap = CorrectMap()
10011001
for i, answer_id in enumerate(answer_ids):
1002-
queuestate = CodeResponseTest.make_queuestate(i, datetime.now(UTC))
1002+
queuestate = CodeResponseTest.make_queuestate(i, datetime.now(ZoneInfo("UTC")))
10031003
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
10041004
self.problem.correct_map.update(cmap)
10051005

@@ -1015,7 +1015,7 @@ def test_update_score(self): # pylint: disable=too-many-locals
10151015
old_cmap = CorrectMap()
10161016
for i, answer_id in enumerate(answer_ids):
10171017
queuekey = 1000 + i
1018-
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(UTC))
1018+
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(ZoneInfo("UTC")))
10191019
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
10201020

10211021
# Message format common to external graders
@@ -1083,14 +1083,14 @@ def test_recentmost_queuetime(self):
10831083
cmap = CorrectMap()
10841084
for i, answer_id in enumerate(answer_ids):
10851085
queuekey = 1000 + i
1086-
latest_timestamp = datetime.now(UTC)
1086+
latest_timestamp = datetime.now(ZoneInfo("UTC"))
10871087
queuestate = CodeResponseTest.make_queuestate(queuekey, latest_timestamp)
10881088
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
10891089
self.problem.correct_map.update(cmap)
10901090

10911091
# Queue state only tracks up to second
10921092
latest_timestamp = datetime.strptime(datetime.strftime(latest_timestamp, DATEFORMAT), DATEFORMAT).replace(
1093-
tzinfo=UTC
1093+
tzinfo=ZoneInfo("UTC")
10941094
)
10951095

10961096
assert self.problem.get_recentmost_queuetime() == latest_timestamp
@@ -1153,7 +1153,7 @@ def test_parse_score_msg_of_responder(self):
11531153
old_cmap = CorrectMap()
11541154
for i, answer_id in enumerate(answer_ids):
11551155
queuekey = 1000 + i
1156-
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(UTC))
1156+
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(ZoneInfo("UTC")))
11571157
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
11581158

11591159
for grader_msg in valid_grader_msgs:

xmodule/capa_block.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@
2323
from django.utils.encoding import smart_str
2424
from django.utils.functional import cached_property
2525
from lxml import etree
26-
from pytz import utc
2726
from web_fragments.fragment import Fragment
2827
from xblock.core import XBlock
2928
from xblock.exceptions import NotFoundError, ProcessingError
@@ -62,6 +61,7 @@
6261
from xmodule.util.sandboxing import SandboxService
6362
from xmodule.x_module import XModuleMixin, XModuleToXBlockMixin, shim_xmodule_js
6463
from xmodule.xml_block import XmlMixin
64+
from zoneinfo import ZoneInfo
6565

6666
from .capa.xqueue_interface import XQueueService
6767

@@ -931,7 +931,7 @@ def set_last_submission_time(self):
931931
"""
932932
Set the module's last submission time (when the problem was submitted)
933933
"""
934-
self.last_submission_time = datetime.datetime.now(utc)
934+
self.last_submission_time = datetime.datetime.now(ZoneInfo("UTC"))
935935

936936
def get_progress(self):
937937
"""
@@ -1448,7 +1448,7 @@ def is_past_due(self):
14481448
"""
14491449
Is it now past this problem's due date, including grace period?
14501450
"""
1451-
return self.close_date is not None and datetime.datetime.now(utc) > self.close_date
1451+
return self.close_date is not None and datetime.datetime.now(ZoneInfo("UTC")) > self.close_date
14521452

14531453
def closed(self):
14541454
"""
@@ -1774,7 +1774,7 @@ def submit_problem( # pylint: disable=too-many-statements,too-many-branches,too
17741774
event_info["answers"] = answers_without_files
17751775

17761776
# Can override current time
1777-
current_time = datetime.datetime.now(utc)
1777+
current_time = datetime.datetime.now(ZoneInfo("UTC"))
17781778
if override_time is not False:
17791779
current_time = override_time
17801780

xmodule/course_block.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
from lazy import lazy
1616
from lxml import etree
1717
from path import Path as path
18-
from pytz import utc
1918
from xblock.fields import Boolean, Date, Dict, Float, Integer, List, Scope, String
2019
from openedx.core.djangoapps.video_pipeline.models import VideoUploadsEnabledByDefault
2120
from openedx.core.djangoapps.video_config.sharing import (
@@ -31,6 +30,7 @@
3130
from xmodule.graders import grader_from_conf
3231
from xmodule.seq_block import SequenceBlock
3332
from xmodule.tabs import CourseTabList, InvalidTabsException
33+
from zoneinfo import ZoneInfo
3434

3535
from .modulestore.exceptions import InvalidProctoringProvider
3636

@@ -163,7 +163,7 @@ def table_of_contents(self):
163163
# see if we already fetched this
164164
if toc_url in _cached_toc:
165165
(table_of_contents, timestamp) = _cached_toc[toc_url]
166-
age = datetime.now(utc) - timestamp
166+
age = datetime.now(ZoneInfo("UTC")) - timestamp
167167
# expire every 10 minutes
168168
if age.seconds < 600:
169169
return table_of_contents
@@ -1485,7 +1485,7 @@ def forum_posts_allowed(self):
14851485

14861486
blackouts = self.get_discussion_blackout_datetimes()
14871487
posting_restrictions = self.discussions_settings.get('posting_restrictions', 'disabled')
1488-
now = datetime.now(utc)
1488+
now = datetime.now(ZoneInfo("UTC"))
14891489

14901490
if posting_restrictions == 'enabled':
14911491
return False
@@ -1601,7 +1601,7 @@ def can_toggle_course_pacing(self):
16011601
"""
16021602
if not self.start:
16031603
return False
1604-
return datetime.now(utc) <= self.start
1604+
return datetime.now(ZoneInfo("UTC")) <= self.start
16051605

16061606

16071607
class CourseSummary:
@@ -1674,5 +1674,5 @@ def has_ended(self):
16741674
course_id=str(self.id), end_date=self.end, err=e
16751675
)
16761676
)
1677-
modified_end = self.end.replace(tzinfo=utc)
1677+
modified_end = self.end.replace(tzinfo=ZoneInfo("UTC"))
16781678
return course_metadata_utils.has_course_ended(modified_end)

xmodule/course_metadata_utils.py

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,9 @@
1212
from math import exp
1313

1414
import dateutil.parser
15-
from pytz import utc
15+
from zoneinfo import ZoneInfo
1616

17-
DEFAULT_START_DATE = datetime(2030, 1, 1, tzinfo=utc)
17+
DEFAULT_START_DATE = datetime(2030, 1, 1, tzinfo=ZoneInfo("UTC"))
1818

1919
"""
2020
Default grading policy for a course run.
@@ -95,7 +95,7 @@ def has_course_started(start_date):
9595
start_date (datetime): The start datetime of the course in question.
9696
"""
9797
# TODO: This will throw if start_date is None... consider changing this behavior?
98-
return datetime.now(utc) > start_date
98+
return datetime.now(ZoneInfo("UTC")) > start_date
9999

100100

101101
def has_course_ended(end_date):
@@ -107,7 +107,7 @@ def has_course_ended(end_date):
107107
Arguments:
108108
end_date (datetime): The end datetime of the course in question.
109109
"""
110-
return datetime.now(utc) > end_date if end_date is not None else False
110+
return datetime.now(ZoneInfo("UTC")) > end_date if end_date is not None else False
111111

112112

113113
def is_enrollment_open(enrollment_start_date, enrollment_end_date):
@@ -118,9 +118,9 @@ def is_enrollment_open(enrollment_start_date, enrollment_end_date):
118118
enrollment_start_date (datetime): The enrollment start datetime of the course.
119119
enrollment_end_date (datetime): The enrollment end datetime of the course.
120120
"""
121-
now = datetime.now(utc)
122-
enrollment_start_date = enrollment_start_date or datetime.min.replace(tzinfo=utc)
123-
enrollment_end_date = enrollment_end_date or datetime.max.replace(tzinfo=utc)
121+
now = datetime.now(ZoneInfo("UTC"))
122+
enrollment_start_date = enrollment_start_date or datetime.min.replace(tzinfo=ZoneInfo("UTC"))
123+
enrollment_end_date = enrollment_end_date or datetime.max.replace(tzinfo=ZoneInfo("UTC"))
124124
return enrollment_start_date < now < enrollment_end_date
125125

126126

@@ -133,7 +133,7 @@ def course_starts_within(start_date, look_ahead_days):
133133
start_date (datetime): The start datetime of the course in question.
134134
look_ahead_days (int): number of days to see in future for course start date.
135135
"""
136-
return datetime.now(utc) + timedelta(days=look_ahead_days) > start_date
136+
return datetime.now(ZoneInfo("UTC")) + timedelta(days=look_ahead_days) > start_date
137137

138138

139139
def course_start_date_is_default(start, advertised_start):
@@ -179,10 +179,10 @@ def sorting_dates(start, advertised_start, announcement):
179179
try:
180180
start = dateutil.parser.parse(advertised_start)
181181
if start.tzinfo is None:
182-
start = start.replace(tzinfo=utc)
182+
start = start.replace(tzinfo=ZoneInfo("UTC"))
183183
except (TypeError, ValueError, AttributeError):
184184
start = start # lint-amnesty, pylint: disable=self-assigning-variable
185185

186-
now = datetime.now(utc)
186+
now = datetime.now(ZoneInfo("UTC"))
187187

188188
return announcement, start, now

xmodule/graders.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
from django.utils.translation import gettext_lazy as _
1414

1515
from xmodule.util.misc import get_short_labeler
16+
from zoneinfo import ZoneInfo
1617

1718

1819
log = logging.getLogger("edx.courseware")

xmodule/lti_block.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,12 +69,12 @@
6969
from lxml import etree
7070
from oauthlib.oauth1.rfc5849 import signature
7171
from opaque_keys.edx.keys import CourseKey
72-
from pytz import UTC
7372
from web_fragments.fragment import Fragment
7473
from webob import Response
7574
from xblock.core import List, Scope, String, XBlock
7675
from xblock.fields import Boolean, Float
7776
from xblocks_contrib.lti import LTIBlock as _ExtractedLTIBlock
77+
from zoneinfo import ZoneInfo
7878

7979
from common.djangoapps.xblock_django.constants import (
8080
ATTR_KEY_ANONYMOUS_USER_ID,
@@ -989,7 +989,7 @@ def is_past_due(self):
989989
close_date = due_date + self.graceperiod # pylint: disable=no-member
990990
else:
991991
close_date = due_date
992-
return close_date is not None and datetime.datetime.now(UTC) > close_date
992+
return close_date is not None and datetime.datetime.now(ZoneInfo("UTC")) > close_date
993993

994994

995995
LTIBlock = (

xmodule/modulestore/__init__.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,6 @@
1616

1717
from opaque_keys.edx.keys import AssetKey, CourseKey
1818
from opaque_keys.edx.locations import Location # For import backwards compatibility
19-
from pytz import UTC
2019
from sortedcontainers import SortedKeyList
2120
from xblock.core import XBlock
2221
from xblock.plugin import default_select
@@ -28,6 +27,7 @@
2827
from xmodule.assetstore import AssetMetadata
2928
from xmodule.errortracker import make_error_tracker
3029
from xmodule.util.misc import get_library_or_course_attribute
30+
from zoneinfo import ZoneInfo
3131

3232
from .exceptions import InsufficientSpecificationError, InvalidLocationError
3333

@@ -719,7 +719,7 @@ def _save_assets_by_type(self, course_key, asset_metadata_list, course_assets, u
719719
))
720720
continue
721721
if not import_only:
722-
asset_md.update({'edited_by': user_id, 'edited_on': datetime.datetime.now(UTC)})
722+
asset_md.update({'edited_by': user_id, 'edited_on': datetime.datetime.now(ZoneInfo("UTC"))})
723723
asset_type = asset_md.asset_id.asset_type
724724
all_assets = assets_by_type[asset_type]
725725
all_assets.insert_or_update(asset_md)
@@ -862,7 +862,7 @@ def _block_matches(self, block, qualifiers):
862862
For substring matching:
863863
pass a regex object.
864864
For arbitrary function comparison such as date time comparison:
865-
pass the function as in start=lambda x: x < datetime.datetime(2014, 1, 1, 0, tzinfo=pytz.UTC)
865+
pass the function as in start=lambda x: x < datetime.datetime(2014, 1, 1, 0, tzinfo=ZoneInfo("UTC"))
866866
867867
Args:
868868
block (dict, XBlock, or BlockData): either the BlockData (transformed from the db) -or-

0 commit comments

Comments
 (0)