Skip to content

Commit f841763

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

27 files changed

Lines changed: 126 additions & 122 deletions

xmodule/assetstore/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55

66
import json
77
from datetime import datetime
8+
from zoneinfo import ZoneInfo
89

910
import dateutil.parser
10-
import pytz
1111
from lxml import etree
1212
from opaque_keys.edx.keys import AssetKey, CourseKey
1313

@@ -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
@@ -23,10 +23,10 @@
2323
from datetime import datetime
2424
from typing import Optional
2525
from xml.sax.saxutils import unescape
26+
from zoneinfo import ZoneInfo
2627

2728
from django.conf import settings
2829
from lxml import etree
29-
from pytz import UTC
3030

3131
from openedx.core.djangolib.markup import HTML, Text
3232
from openedx.core.lib.safe_lxml.xmlparser import XML
@@ -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
@@ -20,6 +20,7 @@
2020
from collections import namedtuple
2121
from datetime import datetime
2222
from sys import float_info
23+
from zoneinfo import ZoneInfo
2324

2425
import html5lib
2526
import numpy
@@ -33,7 +34,6 @@
3334
from lxml import etree
3435
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
3536
from pyparsing import ParseException
36-
from pytz import UTC
3737
from shapely.geometry import MultiPoint, Point
3838
from six.moves import map, range, zip
3939
from symmath import symmath_check
@@ -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
@@ -11,13 +11,13 @@
1111
import zipfile
1212
from datetime import datetime
1313
from unittest import mock
14+
from zoneinfo import ZoneInfo
1415

1516
import calc
1617
import pyparsing
1718
import pytest
1819
import random2 as random
1920
import requests
20-
from pytz import UTC
2121

2222
from xmodule.capa.correctmap import CorrectMap
2323
from xmodule.capa.responsetypes import (
@@ -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
@@ -15,6 +15,7 @@
1515
import struct
1616
import sys
1717
import traceback
18+
from zoneinfo import ZoneInfo
1819

1920
import nh3
2021
from django.conf import settings
@@ -23,7 +24,6 @@
2324
from django.utils.encoding import smart_str
2425
from django.utils.functional import cached_property
2526
from lxml import etree
26-
from pytz import utc
2727
from web_fragments.fragment import Fragment
2828
from xblock.core import XBlock
2929
from xblock.exceptions import NotFoundError, ProcessingError
@@ -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
@@ -6,6 +6,7 @@
66
import json
77
import logging
88
from datetime import datetime, timedelta
9+
from zoneinfo import ZoneInfo
910

1011
import dateutil.parser
1112
import requests
@@ -15,7 +16,6 @@
1516
from lazy import lazy
1617
from lxml import etree
1718
from path import Path as path
18-
from pytz import utc
1919
from xblock.fields import Boolean, Date, Dict, Float, Integer, List, Scope, String
2020
from openedx.core.djangoapps.video_pipeline.models import VideoUploadsEnabledByDefault
2121
from openedx.core.djangoapps.video_config.sharing import (
@@ -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: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,15 @@
77
"""
88

99

10+
import dateutil.parser
11+
1012
from base64 import b32encode
1113
from datetime import datetime, timedelta
1214
from math import exp
15+
from zoneinfo import ZoneInfo
1316

14-
import dateutil.parser
15-
from pytz import utc
1617

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

1920
"""
2021
Default grading policy for a course run.
@@ -95,7 +96,7 @@ def has_course_started(start_date):
9596
start_date (datetime): The start datetime of the course in question.
9697
"""
9798
# TODO: This will throw if start_date is None... consider changing this behavior?
98-
return datetime.now(utc) > start_date
99+
return datetime.now(ZoneInfo("UTC")) > start_date
99100

100101

101102
def has_course_ended(end_date):
@@ -107,7 +108,7 @@ def has_course_ended(end_date):
107108
Arguments:
108109
end_date (datetime): The end datetime of the course in question.
109110
"""
110-
return datetime.now(utc) > end_date if end_date is not None else False
111+
return datetime.now(ZoneInfo("UTC")) > end_date if end_date is not None else False
111112

112113

113114
def is_enrollment_open(enrollment_start_date, enrollment_end_date):
@@ -118,9 +119,9 @@ def is_enrollment_open(enrollment_start_date, enrollment_end_date):
118119
enrollment_start_date (datetime): The enrollment start datetime of the course.
119120
enrollment_end_date (datetime): The enrollment end datetime of the course.
120121
"""
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)
122+
now = datetime.now(ZoneInfo("UTC"))
123+
enrollment_start_date = enrollment_start_date or datetime.min.replace(tzinfo=ZoneInfo("UTC"))
124+
enrollment_end_date = enrollment_end_date or datetime.max.replace(tzinfo=ZoneInfo("UTC"))
124125
return enrollment_start_date < now < enrollment_end_date
125126

126127

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

138139

139140
def course_start_date_is_default(start, advertised_start):
@@ -179,10 +180,10 @@ def sorting_dates(start, advertised_start, announcement):
179180
try:
180181
start = dateutil.parser.parse(advertised_start)
181182
if start.tzinfo is None:
182-
start = start.replace(tzinfo=utc)
183+
start = start.replace(tzinfo=ZoneInfo("UTC"))
183184
except (TypeError, ValueError, AttributeError):
184185
start = start # lint-amnesty, pylint: disable=self-assigning-variable
185186

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

188189
return announcement, start, now

xmodule/lti_block.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,14 +62,14 @@
6262
from unittest import mock
6363
from urllib import parse
6464
from xml.sax.saxutils import escape
65+
from zoneinfo import ZoneInfo
6566

6667
import nh3
6768
import oauthlib.oauth1
6869
from django.conf import settings
6970
from lxml import etree
7071
from oauthlib.oauth1.rfc5849 import signature
7172
from opaque_keys.edx.keys import CourseKey
72-
from pytz import UTC
7373
from web_fragments.fragment import Fragment
7474
from webob import Response
7575
from xblock.core import List, Scope, String, XBlock
@@ -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: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,11 @@
1212
from collections import defaultdict
1313
from contextlib import contextmanager
1414
from operator import itemgetter
15-
from django.db import transaction
15+
from zoneinfo import ZoneInfo
1616

17+
from django.db import transaction
1718
from opaque_keys.edx.keys import AssetKey, CourseKey
1819
from opaque_keys.edx.locations import Location # For import backwards compatibility
19-
from pytz import UTC
2020
from sortedcontainers import SortedKeyList
2121
from xblock.core import XBlock
2222
from xblock.plugin import default_select
@@ -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-

xmodule/modulestore/mongo/base.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,14 @@
1919
from datetime import datetime
2020
from importlib import import_module
2121
from uuid import uuid4
22+
from zoneinfo import ZoneInfo
2223

2324
import pymongo
2425
from bson.son import SON
2526
from fs.osfs import OSFS
2627
from opaque_keys.edx.keys import CourseKey, UsageKey
2728
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator
2829
from path import Path as path
29-
from pytz import UTC
3030
from xblock.exceptions import InvalidScopeError
3131
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope, ScopeIds
3232
from xblock.runtime import KvsFieldData
@@ -252,7 +252,7 @@ def load_item(self, location, for_parent=None): # lint-amnesty, pylint: disable
252252
if raw_metadata.get('published_date'):
253253
block._edit_info['published_date'] = datetime(
254254
*raw_metadata.get('published_date')[0:6]
255-
).replace(tzinfo=UTC)
255+
).replace(tzinfo=ZoneInfo("UTC"))
256256
block._edit_info['published_by'] = raw_metadata.get('published_by')
257257

258258
for wrapper in self.modulestore.xblock_field_data_wrappers:

0 commit comments

Comments
 (0)