chore: use zoneinfo instead of pytz
This commit is contained in:
@@ -5,9 +5,9 @@ Classes representing asset metadata.
|
|||||||
|
|
||||||
import json
|
import json
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
import pytz
|
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from opaque_keys.edx.keys import AssetKey, CourseKey
|
from opaque_keys.edx.keys import AssetKey, CourseKey
|
||||||
|
|
||||||
@@ -80,7 +80,7 @@ class AssetMetadata:
|
|||||||
self.thumbnail = thumbnail
|
self.thumbnail = thumbnail
|
||||||
self.curr_version = curr_version
|
self.curr_version = curr_version
|
||||||
self.prev_version = prev_version
|
self.prev_version = prev_version
|
||||||
now = datetime.now(pytz.utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
self.edited_by = edited_by
|
self.edited_by = edited_by
|
||||||
self.edited_by_email = edited_by_email
|
self.edited_by_email = edited_by_email
|
||||||
self.edited_on = edited_on or now
|
self.edited_on = edited_on or now
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ from copy import deepcopy
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import Optional
|
from typing import Optional
|
||||||
from xml.sax.saxutils import unescape
|
from xml.sax.saxutils import unescape
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from pytz import UTC
|
|
||||||
|
|
||||||
from openedx.core.djangolib.markup import HTML, Text
|
from openedx.core.djangolib.markup import HTML, Text
|
||||||
from openedx.core.lib.safe_lxml.xmlparser import XML
|
from openedx.core.lib.safe_lxml.xmlparser import XML
|
||||||
@@ -437,7 +437,10 @@ class LoncapaProblem: # pylint: disable=too-many-public-methods,too-many-instan
|
|||||||
if self.correct_map.is_queued(answer_id)
|
if self.correct_map.is_queued(answer_id)
|
||||||
]
|
]
|
||||||
queuetimes = [
|
queuetimes = [
|
||||||
datetime.strptime(qt_str, xqueue_interface.DATEFORMAT).replace(tzinfo=UTC) for qt_str in queuetime_strs
|
datetime.strptime(qt_str, xqueue_interface.DATEFORMAT).replace(
|
||||||
|
tzinfo=ZoneInfo("UTC")
|
||||||
|
)
|
||||||
|
for qt_str in queuetime_strs
|
||||||
]
|
]
|
||||||
|
|
||||||
return max(queuetimes)
|
return max(queuetimes)
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ from cmath import isnan
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from sys import float_info
|
from sys import float_info
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import html5lib
|
import html5lib
|
||||||
import numpy
|
import numpy
|
||||||
@@ -33,7 +34,6 @@ from django.utils import html
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
|
from lxml.html.soupparser import fromstring as fromstring_bs # uses Beautiful Soup!!! FIXME?
|
||||||
from pyparsing import ParseException
|
from pyparsing import ParseException
|
||||||
from pytz import UTC
|
|
||||||
from shapely.geometry import MultiPoint, Point
|
from shapely.geometry import MultiPoint, Point
|
||||||
from six.moves import map, range, zip
|
from six.moves import map, range, zip
|
||||||
from symmath import symmath_check
|
from symmath import symmath_check
|
||||||
@@ -2653,7 +2653,7 @@ class CodeResponse(LoncapaResponse):
|
|||||||
# ------------------------------------------------------------
|
# ------------------------------------------------------------
|
||||||
|
|
||||||
qinterface = self.capa_system.xqueue.interface
|
qinterface = self.capa_system.xqueue.interface
|
||||||
qtime = datetime.strftime(datetime.now(UTC), DATEFORMAT)
|
qtime = datetime.strftime(datetime.now(ZoneInfo("UTC")), DATEFORMAT)
|
||||||
|
|
||||||
anonymous_student_id = self.capa_system.anonymous_student_id
|
anonymous_student_id = self.capa_system.anonymous_student_id
|
||||||
|
|
||||||
|
|||||||
@@ -11,13 +11,13 @@ import unittest
|
|||||||
import zipfile
|
import zipfile
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import calc
|
import calc
|
||||||
import pyparsing
|
import pyparsing
|
||||||
import pytest
|
import pytest
|
||||||
import random2 as random
|
import random2 as random
|
||||||
import requests
|
import requests
|
||||||
from pytz import UTC
|
|
||||||
|
|
||||||
from xmodule.capa.correctmap import CorrectMap
|
from xmodule.capa.correctmap import CorrectMap
|
||||||
from xmodule.capa.responsetypes import (
|
from xmodule.capa.responsetypes import (
|
||||||
@@ -999,7 +999,7 @@ class CodeResponseTest(ResponseTest):
|
|||||||
# Now we queue the LCP
|
# Now we queue the LCP
|
||||||
cmap = CorrectMap()
|
cmap = CorrectMap()
|
||||||
for i, answer_id in enumerate(answer_ids):
|
for i, answer_id in enumerate(answer_ids):
|
||||||
queuestate = CodeResponseTest.make_queuestate(i, datetime.now(UTC))
|
queuestate = CodeResponseTest.make_queuestate(i, datetime.now(ZoneInfo("UTC")))
|
||||||
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
||||||
self.problem.correct_map.update(cmap)
|
self.problem.correct_map.update(cmap)
|
||||||
|
|
||||||
@@ -1015,7 +1015,7 @@ class CodeResponseTest(ResponseTest):
|
|||||||
old_cmap = CorrectMap()
|
old_cmap = CorrectMap()
|
||||||
for i, answer_id in enumerate(answer_ids):
|
for i, answer_id in enumerate(answer_ids):
|
||||||
queuekey = 1000 + i
|
queuekey = 1000 + i
|
||||||
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(UTC))
|
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(ZoneInfo("UTC")))
|
||||||
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
||||||
|
|
||||||
# Message format common to external graders
|
# Message format common to external graders
|
||||||
@@ -1083,14 +1083,14 @@ class CodeResponseTest(ResponseTest):
|
|||||||
cmap = CorrectMap()
|
cmap = CorrectMap()
|
||||||
for i, answer_id in enumerate(answer_ids):
|
for i, answer_id in enumerate(answer_ids):
|
||||||
queuekey = 1000 + i
|
queuekey = 1000 + i
|
||||||
latest_timestamp = datetime.now(UTC)
|
latest_timestamp = datetime.now(ZoneInfo("UTC"))
|
||||||
queuestate = CodeResponseTest.make_queuestate(queuekey, latest_timestamp)
|
queuestate = CodeResponseTest.make_queuestate(queuekey, latest_timestamp)
|
||||||
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
||||||
self.problem.correct_map.update(cmap)
|
self.problem.correct_map.update(cmap)
|
||||||
|
|
||||||
# Queue state only tracks up to second
|
# Queue state only tracks up to second
|
||||||
latest_timestamp = datetime.strptime(datetime.strftime(latest_timestamp, DATEFORMAT), DATEFORMAT).replace(
|
latest_timestamp = datetime.strptime(datetime.strftime(latest_timestamp, DATEFORMAT), DATEFORMAT).replace(
|
||||||
tzinfo=UTC
|
tzinfo=ZoneInfo("UTC")
|
||||||
)
|
)
|
||||||
|
|
||||||
assert self.problem.get_recentmost_queuetime() == latest_timestamp
|
assert self.problem.get_recentmost_queuetime() == latest_timestamp
|
||||||
@@ -1153,7 +1153,7 @@ class CodeResponseTest(ResponseTest):
|
|||||||
old_cmap = CorrectMap()
|
old_cmap = CorrectMap()
|
||||||
for i, answer_id in enumerate(answer_ids):
|
for i, answer_id in enumerate(answer_ids):
|
||||||
queuekey = 1000 + i
|
queuekey = 1000 + i
|
||||||
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(UTC))
|
queuestate = CodeResponseTest.make_queuestate(queuekey, datetime.now(ZoneInfo("UTC")))
|
||||||
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
old_cmap.update(CorrectMap(answer_id=answer_id, queuestate=queuestate))
|
||||||
|
|
||||||
for grader_msg in valid_grader_msgs:
|
for grader_msg in valid_grader_msgs:
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import re
|
|||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import nh3
|
import nh3
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
@@ -23,7 +24,6 @@ from django.template.loader import render_to_string
|
|||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
from django.utils.functional import cached_property
|
from django.utils.functional import cached_property
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from pytz import utc
|
|
||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
from xblock.exceptions import NotFoundError, ProcessingError
|
from xblock.exceptions import NotFoundError, ProcessingError
|
||||||
@@ -931,7 +931,7 @@ class _BuiltInProblemBlock( # pylint: disable=too-many-public-methods,too-many-
|
|||||||
"""
|
"""
|
||||||
Set the module's last submission time (when the problem was submitted)
|
Set the module's last submission time (when the problem was submitted)
|
||||||
"""
|
"""
|
||||||
self.last_submission_time = datetime.datetime.now(utc)
|
self.last_submission_time = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
def get_progress(self):
|
def get_progress(self):
|
||||||
"""
|
"""
|
||||||
@@ -1448,7 +1448,7 @@ class _BuiltInProblemBlock( # pylint: disable=too-many-public-methods,too-many-
|
|||||||
"""
|
"""
|
||||||
Is it now past this problem's due date, including grace period?
|
Is it now past this problem's due date, including grace period?
|
||||||
"""
|
"""
|
||||||
return self.close_date is not None and datetime.datetime.now(utc) > self.close_date
|
return self.close_date is not None and datetime.datetime.now(ZoneInfo("UTC")) > self.close_date
|
||||||
|
|
||||||
def closed(self):
|
def closed(self):
|
||||||
"""
|
"""
|
||||||
@@ -1774,7 +1774,7 @@ class _BuiltInProblemBlock( # pylint: disable=too-many-public-methods,too-many-
|
|||||||
event_info["answers"] = answers_without_files
|
event_info["answers"] = answers_without_files
|
||||||
|
|
||||||
# Can override current time
|
# Can override current time
|
||||||
current_time = datetime.datetime.now(utc)
|
current_time = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
if override_time is not False:
|
if override_time is not False:
|
||||||
current_time = override_time
|
current_time = override_time
|
||||||
|
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ Django module container for classes and operations related to the "Course Block"
|
|||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import dateutil.parser
|
import dateutil.parser
|
||||||
import requests
|
import requests
|
||||||
@@ -15,7 +16,6 @@ from edx_toggles.toggles import SettingDictToggle
|
|||||||
from lazy import lazy
|
from lazy import lazy
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from path import Path as path
|
from path import Path as path
|
||||||
from pytz import utc
|
|
||||||
from xblock.fields import Boolean, Date, Dict, Float, Integer, List, Scope, String
|
from xblock.fields import Boolean, Date, Dict, Float, Integer, List, Scope, String
|
||||||
from openedx.core.djangoapps.video_pipeline.models import VideoUploadsEnabledByDefault
|
from openedx.core.djangoapps.video_pipeline.models import VideoUploadsEnabledByDefault
|
||||||
from openedx.core.djangoapps.video_config.sharing import (
|
from openedx.core.djangoapps.video_config.sharing import (
|
||||||
@@ -163,7 +163,7 @@ class Textbook: # lint-amnesty, pylint: disable=missing-class-docstring
|
|||||||
# see if we already fetched this
|
# see if we already fetched this
|
||||||
if toc_url in _cached_toc:
|
if toc_url in _cached_toc:
|
||||||
(table_of_contents, timestamp) = _cached_toc[toc_url]
|
(table_of_contents, timestamp) = _cached_toc[toc_url]
|
||||||
age = datetime.now(utc) - timestamp
|
age = datetime.now(ZoneInfo("UTC")) - timestamp
|
||||||
# expire every 10 minutes
|
# expire every 10 minutes
|
||||||
if age.seconds < 600:
|
if age.seconds < 600:
|
||||||
return table_of_contents
|
return table_of_contents
|
||||||
@@ -1485,7 +1485,7 @@ class CourseBlock(
|
|||||||
|
|
||||||
blackouts = self.get_discussion_blackout_datetimes()
|
blackouts = self.get_discussion_blackout_datetimes()
|
||||||
posting_restrictions = self.discussions_settings.get('posting_restrictions', 'disabled')
|
posting_restrictions = self.discussions_settings.get('posting_restrictions', 'disabled')
|
||||||
now = datetime.now(utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
if posting_restrictions == 'enabled':
|
if posting_restrictions == 'enabled':
|
||||||
return False
|
return False
|
||||||
@@ -1601,7 +1601,7 @@ class CourseBlock(
|
|||||||
"""
|
"""
|
||||||
if not self.start:
|
if not self.start:
|
||||||
return False
|
return False
|
||||||
return datetime.now(utc) <= self.start
|
return datetime.now(ZoneInfo("UTC")) <= self.start
|
||||||
|
|
||||||
|
|
||||||
class CourseSummary:
|
class CourseSummary:
|
||||||
@@ -1674,5 +1674,5 @@ class CourseSummary:
|
|||||||
course_id=str(self.id), end_date=self.end, err=e
|
course_id=str(self.id), end_date=self.end, err=e
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
modified_end = self.end.replace(tzinfo=utc)
|
modified_end = self.end.replace(tzinfo=ZoneInfo("UTC"))
|
||||||
return course_metadata_utils.has_course_ended(modified_end)
|
return course_metadata_utils.has_course_ended(modified_end)
|
||||||
|
|||||||
@@ -7,14 +7,15 @@ classes, which both need these type of functions.
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import dateutil.parser
|
||||||
|
|
||||||
from base64 import b32encode
|
from base64 import b32encode
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from math import exp
|
from math import exp
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import dateutil.parser
|
|
||||||
from pytz import utc
|
|
||||||
|
|
||||||
DEFAULT_START_DATE = datetime(2030, 1, 1, tzinfo=utc)
|
DEFAULT_START_DATE = datetime(2030, 1, 1, tzinfo=ZoneInfo("UTC"))
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Default grading policy for a course run.
|
Default grading policy for a course run.
|
||||||
@@ -95,7 +96,7 @@ def has_course_started(start_date):
|
|||||||
start_date (datetime): The start datetime of the course in question.
|
start_date (datetime): The start datetime of the course in question.
|
||||||
"""
|
"""
|
||||||
# TODO: This will throw if start_date is None... consider changing this behavior?
|
# TODO: This will throw if start_date is None... consider changing this behavior?
|
||||||
return datetime.now(utc) > start_date
|
return datetime.now(ZoneInfo("UTC")) > start_date
|
||||||
|
|
||||||
|
|
||||||
def has_course_ended(end_date):
|
def has_course_ended(end_date):
|
||||||
@@ -107,7 +108,7 @@ def has_course_ended(end_date):
|
|||||||
Arguments:
|
Arguments:
|
||||||
end_date (datetime): The end datetime of the course in question.
|
end_date (datetime): The end datetime of the course in question.
|
||||||
"""
|
"""
|
||||||
return datetime.now(utc) > end_date if end_date is not None else False
|
return datetime.now(ZoneInfo("UTC")) > end_date if end_date is not None else False
|
||||||
|
|
||||||
|
|
||||||
def is_enrollment_open(enrollment_start_date, enrollment_end_date):
|
def is_enrollment_open(enrollment_start_date, enrollment_end_date):
|
||||||
@@ -118,9 +119,9 @@ def is_enrollment_open(enrollment_start_date, enrollment_end_date):
|
|||||||
enrollment_start_date (datetime): The enrollment start datetime of the course.
|
enrollment_start_date (datetime): The enrollment start datetime of the course.
|
||||||
enrollment_end_date (datetime): The enrollment end datetime of the course.
|
enrollment_end_date (datetime): The enrollment end datetime of the course.
|
||||||
"""
|
"""
|
||||||
now = datetime.now(utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
enrollment_start_date = enrollment_start_date or datetime.min.replace(tzinfo=utc)
|
enrollment_start_date = enrollment_start_date or datetime.min.replace(tzinfo=ZoneInfo("UTC"))
|
||||||
enrollment_end_date = enrollment_end_date or datetime.max.replace(tzinfo=utc)
|
enrollment_end_date = enrollment_end_date or datetime.max.replace(tzinfo=ZoneInfo("UTC"))
|
||||||
return enrollment_start_date < now < enrollment_end_date
|
return enrollment_start_date < now < enrollment_end_date
|
||||||
|
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ def course_starts_within(start_date, look_ahead_days):
|
|||||||
start_date (datetime): The start datetime of the course in question.
|
start_date (datetime): The start datetime of the course in question.
|
||||||
look_ahead_days (int): number of days to see in future for course start date.
|
look_ahead_days (int): number of days to see in future for course start date.
|
||||||
"""
|
"""
|
||||||
return datetime.now(utc) + timedelta(days=look_ahead_days) > start_date
|
return datetime.now(ZoneInfo("UTC")) + timedelta(days=look_ahead_days) > start_date
|
||||||
|
|
||||||
|
|
||||||
def course_start_date_is_default(start, advertised_start):
|
def course_start_date_is_default(start, advertised_start):
|
||||||
@@ -179,10 +180,10 @@ def sorting_dates(start, advertised_start, announcement):
|
|||||||
try:
|
try:
|
||||||
start = dateutil.parser.parse(advertised_start)
|
start = dateutil.parser.parse(advertised_start)
|
||||||
if start.tzinfo is None:
|
if start.tzinfo is None:
|
||||||
start = start.replace(tzinfo=utc)
|
start = start.replace(tzinfo=ZoneInfo("UTC"))
|
||||||
except (TypeError, ValueError, AttributeError):
|
except (TypeError, ValueError, AttributeError):
|
||||||
start = start # lint-amnesty, pylint: disable=self-assigning-variable
|
start = start # lint-amnesty, pylint: disable=self-assigning-variable
|
||||||
|
|
||||||
now = datetime.now(utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
return announcement, start, now
|
return announcement, start, now
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ import textwrap
|
|||||||
from unittest import mock
|
from unittest import mock
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
from xml.sax.saxutils import escape
|
from xml.sax.saxutils import escape
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import nh3
|
import nh3
|
||||||
import oauthlib.oauth1
|
import oauthlib.oauth1
|
||||||
@@ -69,7 +70,6 @@ from django.conf import settings
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from oauthlib.oauth1.rfc5849 import signature
|
from oauthlib.oauth1.rfc5849 import signature
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
from pytz import UTC
|
|
||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
from webob import Response
|
from webob import Response
|
||||||
from xblock.core import List, Scope, String, XBlock
|
from xblock.core import List, Scope, String, XBlock
|
||||||
@@ -989,7 +989,7 @@ oauth_consumer_key="", oauth_signature="frVp4JuvT1mVXlxktiAUjQ7%2F1cw%3D"'}
|
|||||||
close_date = due_date + self.graceperiod # pylint: disable=no-member
|
close_date = due_date + self.graceperiod # pylint: disable=no-member
|
||||||
else:
|
else:
|
||||||
close_date = due_date
|
close_date = due_date
|
||||||
return close_date is not None and datetime.datetime.now(UTC) > close_date
|
return close_date is not None and datetime.datetime.now(ZoneInfo("UTC")) > close_date
|
||||||
|
|
||||||
|
|
||||||
LTIBlock = (
|
LTIBlock = (
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ from abc import ABCMeta, abstractmethod
|
|||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from operator import itemgetter
|
from operator import itemgetter
|
||||||
from django.db import transaction
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
from django.db import transaction
|
||||||
from opaque_keys.edx.keys import AssetKey, CourseKey
|
from opaque_keys.edx.keys import AssetKey, CourseKey
|
||||||
from opaque_keys.edx.locations import Location # For import backwards compatibility
|
from opaque_keys.edx.locations import Location # For import backwards compatibility
|
||||||
from pytz import UTC
|
|
||||||
from sortedcontainers import SortedKeyList
|
from sortedcontainers import SortedKeyList
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
from xblock.plugin import default_select
|
from xblock.plugin import default_select
|
||||||
@@ -719,7 +719,7 @@ class ModuleStoreAssetWriteInterface(ModuleStoreAssetBase):
|
|||||||
))
|
))
|
||||||
continue
|
continue
|
||||||
if not import_only:
|
if not import_only:
|
||||||
asset_md.update({'edited_by': user_id, 'edited_on': datetime.datetime.now(UTC)})
|
asset_md.update({'edited_by': user_id, 'edited_on': datetime.datetime.now(ZoneInfo("UTC"))})
|
||||||
asset_type = asset_md.asset_id.asset_type
|
asset_type = asset_md.asset_id.asset_type
|
||||||
all_assets = assets_by_type[asset_type]
|
all_assets = assets_by_type[asset_type]
|
||||||
all_assets.insert_or_update(asset_md)
|
all_assets.insert_or_update(asset_md)
|
||||||
@@ -862,7 +862,7 @@ class ModuleStoreRead(ModuleStoreAssetBase, metaclass=ABCMeta):
|
|||||||
For substring matching:
|
For substring matching:
|
||||||
pass a regex object.
|
pass a regex object.
|
||||||
For arbitrary function comparison such as date time comparison:
|
For arbitrary function comparison such as date time comparison:
|
||||||
pass the function as in start=lambda x: x < datetime.datetime(2014, 1, 1, 0, tzinfo=pytz.UTC)
|
pass the function as in start=lambda x: x < datetime.datetime(2014, 1, 1, 0, tzinfo=ZoneInfo("UTC"))
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
block (dict, XBlock, or BlockData): either the BlockData (transformed from the db) -or-
|
block (dict, XBlock, or BlockData): either the BlockData (transformed from the db) -or-
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import sys
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pymongo
|
import pymongo
|
||||||
from bson.son import SON
|
from bson.son import SON
|
||||||
@@ -26,7 +27,6 @@ from fs.osfs import OSFS
|
|||||||
from opaque_keys.edx.keys import CourseKey, UsageKey
|
from opaque_keys.edx.keys import CourseKey, UsageKey
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator
|
||||||
from path import Path as path
|
from path import Path as path
|
||||||
from pytz import UTC
|
|
||||||
from xblock.exceptions import InvalidScopeError
|
from xblock.exceptions import InvalidScopeError
|
||||||
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope, ScopeIds
|
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope, ScopeIds
|
||||||
from xblock.runtime import KvsFieldData
|
from xblock.runtime import KvsFieldData
|
||||||
@@ -252,7 +252,7 @@ class OldModuleStoreRuntime(ModuleStoreRuntime, EditInfoRuntimeMixin): # pylint
|
|||||||
if raw_metadata.get('published_date'):
|
if raw_metadata.get('published_date'):
|
||||||
block._edit_info['published_date'] = datetime(
|
block._edit_info['published_date'] = datetime(
|
||||||
*raw_metadata.get('published_date')[0:6]
|
*raw_metadata.get('published_date')[0:6]
|
||||||
).replace(tzinfo=UTC)
|
).replace(tzinfo=ZoneInfo("UTC"))
|
||||||
block._edit_info['published_by'] = raw_metadata.get('published_by')
|
block._edit_info['published_by'] = raw_metadata.get('published_by')
|
||||||
|
|
||||||
for wrapper in self.modulestore.xblock_field_data_wrappers:
|
for wrapper in self.modulestore.xblock_field_data_wrappers:
|
||||||
|
|||||||
@@ -11,12 +11,12 @@ import re
|
|||||||
import zlib
|
import zlib
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from time import time
|
from time import time
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from ccx_keys.locator import CCXLocator
|
from ccx_keys.locator import CCXLocator
|
||||||
from django.core.cache import caches, InvalidCacheBackendError
|
from django.core.cache import caches, InvalidCacheBackendError
|
||||||
from django.db.transaction import TransactionManagementError
|
from django.db.transaction import TransactionManagementError
|
||||||
import pymongo
|
import pymongo
|
||||||
import pytz
|
|
||||||
# Import this just to export it
|
# Import this just to export it
|
||||||
from pymongo.errors import DuplicateKeyError # pylint: disable=unused-import
|
from pymongo.errors import DuplicateKeyError # pylint: disable=unused-import
|
||||||
from edx_django_utils import monitoring
|
from edx_django_utils import monitoring
|
||||||
@@ -488,7 +488,7 @@ class MongoPersistenceBackend:
|
|||||||
with TIMER.timer("insert_course_index", course_context):
|
with TIMER.timer("insert_course_index", course_context):
|
||||||
# Set last_update which is used to avoid collisions, unless a subclass already set it before calling super()
|
# Set last_update which is used to avoid collisions, unless a subclass already set it before calling super()
|
||||||
if not self.with_mysql_subclass:
|
if not self.with_mysql_subclass:
|
||||||
course_index['last_update'] = datetime.datetime.now(pytz.utc)
|
course_index['last_update'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
# Insert the new index:
|
# Insert the new index:
|
||||||
self.course_index.insert_one(course_index)
|
self.course_index.insert_one(course_index)
|
||||||
|
|
||||||
@@ -515,7 +515,7 @@ class MongoPersistenceBackend:
|
|||||||
}
|
}
|
||||||
# Set last_update which is used to avoid collisions, unless a subclass already set it before calling super()
|
# Set last_update which is used to avoid collisions, unless a subclass already set it before calling super()
|
||||||
if not self.with_mysql_subclass:
|
if not self.with_mysql_subclass:
|
||||||
course_index['last_update'] = datetime.datetime.now(pytz.utc)
|
course_index['last_update'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
# Update the course index:
|
# Update the course index:
|
||||||
result = self.course_index.replace_one(query, course_index, upsert=False,)
|
result = self.course_index.replace_one(query, course_index, upsert=False,)
|
||||||
if result.modified_count == 0:
|
if result.modified_count == 0:
|
||||||
@@ -729,7 +729,7 @@ class DjangoFlexPersistenceBackend(MongoPersistenceBackend):
|
|||||||
# This is a relatively large hammer for the problem, but we mostly only use one course at a time.
|
# This is a relatively large hammer for the problem, but we mostly only use one course at a time.
|
||||||
RequestCache(namespace="course_index_cache").clear()
|
RequestCache(namespace="course_index_cache").clear()
|
||||||
|
|
||||||
course_index['last_update'] = datetime.datetime.now(pytz.utc)
|
course_index['last_update'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
new_index = SplitModulestoreCourseIndex(**SplitModulestoreCourseIndex.fields_from_v1_schema(course_index))
|
new_index = SplitModulestoreCourseIndex(**SplitModulestoreCourseIndex.fields_from_v1_schema(course_index))
|
||||||
new_index.save()
|
new_index.save()
|
||||||
# Also write to MongoDB, so we can switch back to using it if this new MySQL version doesn't work well.
|
# Also write to MongoDB, so we can switch back to using it if this new MySQL version doesn't work well.
|
||||||
@@ -751,7 +751,7 @@ class DjangoFlexPersistenceBackend(MongoPersistenceBackend):
|
|||||||
# This code is just copying the behavior of the existing MongoPersistenceBackend
|
# This code is just copying the behavior of the existing MongoPersistenceBackend
|
||||||
# See https://github.com/openedx/edx-platform/pull/5200 for context
|
# See https://github.com/openedx/edx-platform/pull/5200 for context
|
||||||
RequestCache(namespace="course_index_cache").clear()
|
RequestCache(namespace="course_index_cache").clear()
|
||||||
course_index['last_update'] = datetime.datetime.now(pytz.utc)
|
course_index['last_update'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
# Find the SplitModulestoreCourseIndex entry that we'll be updating:
|
# Find the SplitModulestoreCourseIndex entry that we'll be updating:
|
||||||
index_obj = SplitModulestoreCourseIndex.objects.get(objectid=course_index["_id"])
|
index_obj = SplitModulestoreCourseIndex.objects.get(objectid=course_index["_id"])
|
||||||
|
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ import datetime
|
|||||||
import logging
|
import logging
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from bson.objectid import ObjectId
|
from bson.objectid import ObjectId
|
||||||
from ccx_keys.locator import CCXBlockUsageLocator, CCXLocator
|
from ccx_keys.locator import CCXBlockUsageLocator, CCXLocator
|
||||||
@@ -72,7 +73,6 @@ from opaque_keys.edx.locator import (
|
|||||||
LocalId,
|
LocalId,
|
||||||
)
|
)
|
||||||
from path import Path as path
|
from path import Path as path
|
||||||
from pytz import UTC
|
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope
|
from xblock.fields import Reference, ReferenceList, ReferenceValueDict, Scope
|
||||||
|
|
||||||
@@ -481,7 +481,7 @@ class SplitBulkWriteMixin(BulkOperationsMixin):
|
|||||||
new_structure['_id'] = ObjectId()
|
new_structure['_id'] = ObjectId()
|
||||||
new_structure['previous_version'] = structure['_id']
|
new_structure['previous_version'] = structure['_id']
|
||||||
new_structure['edited_by'] = user_id
|
new_structure['edited_by'] = user_id
|
||||||
new_structure['edited_on'] = datetime.datetime.now(UTC)
|
new_structure['edited_on'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
new_structure['schema_version'] = self.SCHEMA_VERSION
|
new_structure['schema_version'] = self.SCHEMA_VERSION
|
||||||
|
|
||||||
# If we're in a bulk write, update the structure used there, and mark it as dirty
|
# If we're in a bulk write, update the structure used there, and mark it as dirty
|
||||||
@@ -499,7 +499,7 @@ class SplitBulkWriteMixin(BulkOperationsMixin):
|
|||||||
|
|
||||||
original_usage = block_data.edit_info.original_usage
|
original_usage = block_data.edit_info.original_usage
|
||||||
original_usage_version = block_data.edit_info.original_usage_version
|
original_usage_version = block_data.edit_info.original_usage_version
|
||||||
block_data.edit_info.edited_on = datetime.datetime.now(UTC)
|
block_data.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
block_data.edit_info.edited_by = user_id
|
block_data.edit_info.edited_by = user_id
|
||||||
block_data.edit_info.previous_version = block_data.edit_info.update_version
|
block_data.edit_info.previous_version = block_data.edit_info.update_version
|
||||||
block_data.edit_info.update_version = update_version
|
block_data.edit_info.update_version = update_version
|
||||||
@@ -1499,7 +1499,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
"fields": new_def_data,
|
"fields": new_def_data,
|
||||||
"edit_info": {
|
"edit_info": {
|
||||||
"edited_by": user_id,
|
"edited_by": user_id,
|
||||||
"edited_on": datetime.datetime.now(UTC),
|
"edited_on": datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
"previous_version": None,
|
"previous_version": None,
|
||||||
"original_version": new_id,
|
"original_version": new_id,
|
||||||
},
|
},
|
||||||
@@ -1547,7 +1547,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
new_definition['_id'] = ObjectId()
|
new_definition['_id'] = ObjectId()
|
||||||
new_definition['fields'] = new_def_data
|
new_definition['fields'] = new_def_data
|
||||||
new_definition['edit_info']['edited_by'] = user_id
|
new_definition['edit_info']['edited_by'] = user_id
|
||||||
new_definition['edit_info']['edited_on'] = datetime.datetime.now(UTC)
|
new_definition['edit_info']['edited_on'] = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
# previous version id
|
# previous version id
|
||||||
new_definition['edit_info']['previous_version'] = old_definition['_id']
|
new_definition['edit_info']['previous_version'] = old_definition['_id']
|
||||||
new_definition['schema_version'] = self.SCHEMA_VERSION
|
new_definition['schema_version'] = self.SCHEMA_VERSION
|
||||||
@@ -1886,7 +1886,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
new_fields.update(definition_fields)
|
new_fields.update(definition_fields)
|
||||||
definition_id = self._update_definition_from_data(locator, old_def, new_fields, user_id).definition_id
|
definition_id = self._update_definition_from_data(locator, old_def, new_fields, user_id).definition_id
|
||||||
root_block.definition = definition_id
|
root_block.definition = definition_id
|
||||||
root_block.edit_info.edited_on = datetime.datetime.now(UTC)
|
root_block.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
root_block.edit_info.edited_by = user_id
|
root_block.edit_info.edited_by = user_id
|
||||||
root_block.edit_info.previous_version = root_block.edit_info.update_version
|
root_block.edit_info.previous_version = root_block.edit_info.update_version
|
||||||
root_block.edit_info.update_version = new_id
|
root_block.edit_info.update_version = new_id
|
||||||
@@ -1906,7 +1906,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
'course': get_library_or_course_attribute(locator),
|
'course': get_library_or_course_attribute(locator),
|
||||||
'run': locator.run,
|
'run': locator.run,
|
||||||
'edited_by': user_id,
|
'edited_by': user_id,
|
||||||
'edited_on': datetime.datetime.now(UTC),
|
'edited_on': datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
'versions': versions_dict,
|
'versions': versions_dict,
|
||||||
'schema_version': self.SCHEMA_VERSION,
|
'schema_version': self.SCHEMA_VERSION,
|
||||||
'search_targets': search_targets or {},
|
'search_targets': search_targets or {},
|
||||||
@@ -2414,7 +2414,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
dest_info.edit_info.previous_version = dest_info.edit_info.update_version
|
dest_info.edit_info.previous_version = dest_info.edit_info.update_version
|
||||||
dest_info.edit_info.update_version = old_dest_structure_version
|
dest_info.edit_info.update_version = old_dest_structure_version
|
||||||
dest_info.edit_info.edited_by = user_id
|
dest_info.edit_info.edited_by = user_id
|
||||||
dest_info.edit_info.edited_on = datetime.datetime.now(UTC)
|
dest_info.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
orphans = orig_descendants - new_descendants
|
orphans = orig_descendants - new_descendants
|
||||||
for orphan in orphans:
|
for orphan in orphans:
|
||||||
@@ -2483,7 +2483,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
# from draft to published as part of publishing workflow.
|
# from draft to published as part of publishing workflow.
|
||||||
# Setting it to the source_block_info structure version here breaks split_draft's has_changes() method.
|
# Setting it to the source_block_info structure version here breaks split_draft's has_changes() method.
|
||||||
new_block_info.edit_info.edited_by = user_id
|
new_block_info.edit_info.edited_by = user_id
|
||||||
new_block_info.edit_info.edited_on = datetime.datetime.now(UTC)
|
new_block_info.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
new_block_info.edit_info.original_usage = str(usage_key.replace(branch=None, version_guid=None))
|
new_block_info.edit_info.original_usage = str(usage_key.replace(branch=None, version_guid=None))
|
||||||
new_block_info.edit_info.original_usage_version = source_block_info.edit_info.update_version
|
new_block_info.edit_info.original_usage_version = source_block_info.edit_info.update_version
|
||||||
dest_structure['blocks'][new_block_key] = new_block_info
|
dest_structure['blocks'][new_block_key] = new_block_info
|
||||||
@@ -2541,7 +2541,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
for parent_block_key in parent_block_keys:
|
for parent_block_key in parent_block_keys:
|
||||||
parent_block = new_blocks[parent_block_key]
|
parent_block = new_blocks[parent_block_key]
|
||||||
parent_block.fields['children'].remove(block_key)
|
parent_block.fields['children'].remove(block_key)
|
||||||
parent_block.edit_info.edited_on = datetime.datetime.now(UTC)
|
parent_block.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
parent_block.edit_info.edited_by = user_id
|
parent_block.edit_info.edited_by = user_id
|
||||||
parent_block.edit_info.previous_version = parent_block.edit_info.update_version
|
parent_block.edit_info.previous_version = parent_block.edit_info.update_version
|
||||||
parent_block.edit_info.update_version = new_id
|
parent_block.edit_info.update_version = new_id
|
||||||
@@ -3056,7 +3056,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
'previous_version': None,
|
'previous_version': None,
|
||||||
'original_version': new_id,
|
'original_version': new_id,
|
||||||
'edited_by': user_id,
|
'edited_by': user_id,
|
||||||
'edited_on': datetime.datetime.now(UTC),
|
'edited_on': datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
'blocks': blocks,
|
'blocks': blocks,
|
||||||
'schema_version': self.SCHEMA_VERSION,
|
'schema_version': self.SCHEMA_VERSION,
|
||||||
}
|
}
|
||||||
@@ -3122,7 +3122,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
destination_block.edit_info.previous_version = previous_version
|
destination_block.edit_info.previous_version = previous_version
|
||||||
destination_block.edit_info.update_version = destination_version
|
destination_block.edit_info.update_version = destination_version
|
||||||
destination_block.edit_info.edited_by = user_id
|
destination_block.edit_info.edited_by = user_id
|
||||||
destination_block.edit_info.edited_on = datetime.datetime.now(UTC)
|
destination_block.edit_info.edited_on = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
else:
|
else:
|
||||||
destination_block = self._new_block(
|
destination_block = self._new_block(
|
||||||
user_id, new_block.block_type,
|
user_id, new_block.block_type,
|
||||||
@@ -3196,7 +3196,7 @@ class SplitMongoModuleStore(SplitBulkWriteMixin, ModuleStoreWriteBase):
|
|||||||
'fields': block_fields,
|
'fields': block_fields,
|
||||||
'asides': asides,
|
'asides': asides,
|
||||||
'edit_info': {
|
'edit_info': {
|
||||||
'edited_on': datetime.datetime.now(UTC),
|
'edited_on': datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
'edited_by': user_id,
|
'edited_by': user_id,
|
||||||
'previous_version': None,
|
'previous_version': None,
|
||||||
'update_version': new_id
|
'update_version': new_id
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ from collections import defaultdict
|
|||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from unittest.mock import patch
|
from unittest.mock import patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pymongo.message
|
import pymongo.message
|
||||||
import pytz
|
|
||||||
from factory import Factory, Sequence, lazy_attribute, lazy_attribute_sequence
|
from factory import Factory, Sequence, lazy_attribute, lazy_attribute_sequence
|
||||||
from factory.errors import CyclicDefinitionError
|
from factory.errors import CyclicDefinitionError
|
||||||
from opaque_keys.edx.keys import UsageKey
|
from opaque_keys.edx.keys import UsageKey
|
||||||
@@ -207,7 +207,7 @@ class ToyCourseFactory(SampleCourseFactory):
|
|||||||
'graded': True,
|
'graded': True,
|
||||||
'discussion_topics': {"General": {"id": "i4x-edX-toy-course-2012_Fall"}},
|
'discussion_topics': {"General": {"id": "i4x-edX-toy-course-2012_Fall"}},
|
||||||
'graceperiod': datetime.timedelta(days=2, seconds=21599),
|
'graceperiod': datetime.timedelta(days=2, seconds=21599),
|
||||||
'start': datetime.datetime(2015, 7, 17, 12, tzinfo=pytz.utc),
|
'start': datetime.datetime(2015, 7, 17, 12, tzinfo=ZoneInfo("UTC")),
|
||||||
'xml_attributes': {"filename": ["course/2012_Fall.xml", "course/2012_Fall.xml"]},
|
'xml_attributes': {"filename": ["course/2012_Fall.xml", "course/2012_Fall.xml"]},
|
||||||
'pdf_textbooks': [
|
'pdf_textbooks': [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import unittest
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import pytest
|
import pytest
|
||||||
import ddt
|
import ddt
|
||||||
import pytz
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
@@ -30,7 +30,7 @@ class AssetStoreTestData:
|
|||||||
"""
|
"""
|
||||||
Shared data for constructing test assets.
|
Shared data for constructing test assets.
|
||||||
"""
|
"""
|
||||||
now = datetime.now(pytz.utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
user_id = 144
|
user_id = 144
|
||||||
user_id_long = int(user_id)
|
user_id_long = int(user_id)
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ class TestMongoAssetMetadataStorage(TestCase):
|
|||||||
"""
|
"""
|
||||||
Make a single test asset metadata.
|
Make a single test asset metadata.
|
||||||
"""
|
"""
|
||||||
now = datetime.now(pytz.utc)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
return AssetMetadata(
|
return AssetMetadata(
|
||||||
asset_loc, internal_name='EKMND332DDBK',
|
asset_loc, internal_name='EKMND332DDBK',
|
||||||
pathname='pictures/historical', contenttype='image/jpeg',
|
pathname='pictures/historical', contenttype='image/jpeg',
|
||||||
@@ -322,13 +322,13 @@ class TestMongoAssetMetadataStorage(TestCase):
|
|||||||
('curr_version', 'v1.01'),
|
('curr_version', 'v1.01'),
|
||||||
('prev_version', 'v1.0'),
|
('prev_version', 'v1.0'),
|
||||||
('edited_by', 'Mork'),
|
('edited_by', 'Mork'),
|
||||||
('edited_on', datetime(1969, 1, 1, tzinfo=pytz.utc)),
|
('edited_on', datetime(1969, 1, 1, tzinfo=ZoneInfo("UTC"))),
|
||||||
)
|
)
|
||||||
|
|
||||||
DISALLOWED_ATTRS = (
|
DISALLOWED_ATTRS = (
|
||||||
('asset_id', 'IAmBogus'),
|
('asset_id', 'IAmBogus'),
|
||||||
('created_by', 'Smith'),
|
('created_by', 'Smith'),
|
||||||
('created_on', datetime.now(pytz.utc)),
|
('created_on', datetime.now(ZoneInfo("UTC"))),
|
||||||
)
|
)
|
||||||
|
|
||||||
UNKNOWN_ATTRS = (
|
UNKNOWN_ATTRS = (
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ from shutil import rmtree
|
|||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
from unittest.mock import Mock, call, patch
|
from unittest.mock import Mock, call, patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
from openedx_events.content_authoring.data import CourseData, XBlockData
|
from openedx_events.content_authoring.data import CourseData, XBlockData
|
||||||
@@ -32,7 +33,6 @@ import pytest
|
|||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator # pylint: disable=unused-import
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator, LibraryLocator # pylint: disable=unused-import
|
||||||
from pytz import UTC
|
|
||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
from xblock.core import XBlockAside
|
from xblock.core import XBlockAside
|
||||||
from xblock.fields import Scope, ScopeIds, String
|
from xblock.fields import Scope, ScopeIds, String
|
||||||
@@ -2043,7 +2043,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
'problem'
|
'problem'
|
||||||
)
|
)
|
||||||
assert self.user_id == block.edited_by
|
assert self.user_id == block.edited_by
|
||||||
assert datetime.datetime.now(UTC) > block.edited_on
|
assert datetime.datetime.now(ZoneInfo("UTC")) > block.edited_on
|
||||||
|
|
||||||
@ddt.data(ModuleStoreEnum.Type.split)
|
@ddt.data(ModuleStoreEnum.Type.split)
|
||||||
def test_create_item_populates_subtree_edited_info(self, default_ms):
|
def test_create_item_populates_subtree_edited_info(self, default_ms):
|
||||||
@@ -2054,7 +2054,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
'problem'
|
'problem'
|
||||||
)
|
)
|
||||||
assert self.user_id == block.subtree_edited_by
|
assert self.user_id == block.subtree_edited_by
|
||||||
assert datetime.datetime.now(UTC) > block.subtree_edited_on
|
assert datetime.datetime.now(ZoneInfo("UTC")) > block.subtree_edited_on
|
||||||
|
|
||||||
# Split: wildcard search of draft (find) and split (mysql)
|
# Split: wildcard search of draft (find) and split (mysql)
|
||||||
@ddt.data((ModuleStoreEnum.Type.split, 1, 1, 0))
|
@ddt.data((ModuleStoreEnum.Type.split, 1, 1, 0))
|
||||||
@@ -2202,7 +2202,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
block_id='test_html_no_change'
|
block_id='test_html_no_change'
|
||||||
)
|
)
|
||||||
|
|
||||||
after_create = datetime.datetime.now(UTC)
|
after_create = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
# Verify that all nodes were last edited in the past by create_user
|
# Verify that all nodes were last edited in the past by create_user
|
||||||
for block in [component, child, sibling]:
|
for block in [component, child, sibling]:
|
||||||
check_node(block.location, None, after_create, self.user_id, None, after_create, self.user_id)
|
check_node(block.location, None, after_create, self.user_id, None, after_create, self.user_id)
|
||||||
@@ -2213,7 +2213,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
editing_user = self.user_id - 2
|
editing_user = self.user_id - 2
|
||||||
with self.store.bulk_operations(test_course.id): # TNL-764 bulk ops disabled ancestor updates
|
with self.store.bulk_operations(test_course.id): # TNL-764 bulk ops disabled ancestor updates
|
||||||
component = self.store.update_item(component, editing_user)
|
component = self.store.update_item(component, editing_user)
|
||||||
after_edit = datetime.datetime.now(UTC)
|
after_edit = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
check_node(component.location, after_create, after_edit, editing_user, after_create, after_edit, editing_user)
|
check_node(component.location, after_create, after_edit, editing_user, after_create, after_edit, editing_user)
|
||||||
# but child didn't change
|
# but child didn't change
|
||||||
check_node(child.location, None, after_create, self.user_id, None, after_create, self.user_id)
|
check_node(child.location, None, after_create, self.user_id, None, after_create, self.user_id)
|
||||||
@@ -2223,7 +2223,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
child.display_name = 'Changed Display Name'
|
child.display_name = 'Changed Display Name'
|
||||||
self.store.update_item(child, user_id=editing_user)
|
self.store.update_item(child, user_id=editing_user)
|
||||||
|
|
||||||
after_edit = datetime.datetime.now(UTC)
|
after_edit = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
# Verify that child was last edited between after_create and after_edit by edit_user
|
# Verify that child was last edited between after_create and after_edit by edit_user
|
||||||
check_node(child.location, after_create, after_edit, editing_user, after_create, after_edit, editing_user)
|
check_node(child.location, after_create, after_edit, editing_user, after_create, after_edit, editing_user)
|
||||||
@@ -2283,7 +2283,7 @@ class TestMixedModuleStore(CommonMixedModuleStoreSetup):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Store the current time, then publish
|
# Store the current time, then publish
|
||||||
old_time = datetime.datetime.now(UTC)
|
old_time = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
self.store.publish(component.location, publish_user)
|
self.store.publish(component.location, publish_user)
|
||||||
updated_component = self.store.get_item(component.location)
|
updated_component = self.store.get_item(component.location)
|
||||||
|
|
||||||
|
|||||||
@@ -11,11 +11,11 @@ import logging
|
|||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from edx_django_utils.monitoring import set_custom_attribute
|
from edx_django_utils.monitoring import set_custom_attribute
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from opaque_keys.edx.keys import UsageKey
|
from opaque_keys.edx.keys import UsageKey
|
||||||
from pytz import UTC
|
|
||||||
from web_fragments.fragment import Fragment
|
from web_fragments.fragment import Fragment
|
||||||
from xblock.completable import XBlockCompletionMode
|
from xblock.completable import XBlockCompletionMode
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
@@ -393,7 +393,7 @@ class SequenceBlock(
|
|||||||
return (
|
return (
|
||||||
not date or
|
not date or
|
||||||
not hide_after_date or
|
not hide_after_date or
|
||||||
datetime.now(UTC) < date
|
datetime.now(ZoneInfo("UTC")) < date
|
||||||
)
|
)
|
||||||
|
|
||||||
def gate_entire_sequence_if_it_is_a_timed_exam_and_contains_content_type_gated_problems(self):
|
def gate_entire_sequence_if_it_is_a_timed_exam_and_contains_content_type_gated_problems(self):
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import random
|
|||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import DEFAULT, Mock, PropertyMock, patch
|
from unittest.mock import DEFAULT, Mock, PropertyMock, patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
import pytest
|
import pytest
|
||||||
@@ -21,7 +22,6 @@ from django.test import override_settings
|
|||||||
from django.utils.encoding import smart_str
|
from django.utils.encoding import smart_str
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||||
from pytz import UTC
|
|
||||||
from webob.multidict import MultiDict
|
from webob.multidict import MultiDict
|
||||||
from xblock.exceptions import NotFoundError
|
from xblock.exceptions import NotFoundError
|
||||||
from xblock.field_data import DictFieldData
|
from xblock.field_data import DictFieldData
|
||||||
@@ -213,7 +213,7 @@ class ProblemBlockTest(unittest.TestCase): # pylint: disable=too-many-public-me
|
|||||||
def setUp(self):
|
def setUp(self):
|
||||||
super().setUp()
|
super().setUp()
|
||||||
|
|
||||||
now = datetime.datetime.now(UTC)
|
now = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
day_delta = datetime.timedelta(days=1)
|
day_delta = datetime.timedelta(days=1)
|
||||||
self.yesterday_str = str(now - day_delta)
|
self.yesterday_str = str(now - day_delta)
|
||||||
self.today_str = str(now)
|
self.today_str = str(now)
|
||||||
@@ -731,11 +731,11 @@ class ProblemBlockTest(unittest.TestCase): # pylint: disable=too-many-public-me
|
|||||||
|
|
||||||
# Utility to create a datetime object in the past
|
# Utility to create a datetime object in the past
|
||||||
def past_datetime(days):
|
def past_datetime(days):
|
||||||
return datetime.datetime.now(UTC) - datetime.timedelta(days=days)
|
return datetime.datetime.now(ZoneInfo("UTC")) - datetime.timedelta(days=days)
|
||||||
|
|
||||||
# Utility to create a datetime object in the future
|
# Utility to create a datetime object in the future
|
||||||
def future_datetime(days):
|
def future_datetime(days):
|
||||||
return datetime.datetime.now(UTC) + datetime.timedelta(days=days)
|
return datetime.datetime.now(ZoneInfo("UTC")) + datetime.timedelta(days=days)
|
||||||
|
|
||||||
block = CapaFactory.create(max_attempts="1", attempts="0")
|
block = CapaFactory.create(max_attempts="1", attempts="0")
|
||||||
|
|
||||||
@@ -1258,7 +1258,7 @@ class ProblemBlockTest(unittest.TestCase): # pylint: disable=too-many-public-me
|
|||||||
)
|
)
|
||||||
with multipatch as values:
|
with multipatch as values:
|
||||||
values["is_queued"].return_value = True
|
values["is_queued"].return_value = True
|
||||||
values["get_recentmost_queuetime"].return_value = datetime.datetime.now(UTC)
|
values["get_recentmost_queuetime"].return_value = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
|
|
||||||
get_request_dict = {CapaFactory.input_key(): "3.14"}
|
get_request_dict = {CapaFactory.input_key(): "3.14"}
|
||||||
result = block.submit_problem(get_request_dict)
|
result = block.submit_problem(get_request_dict)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import unittest
|
|||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
import sys
|
import sys
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
from dateutil import parser
|
from dateutil import parser
|
||||||
@@ -14,7 +15,6 @@ from django.test import override_settings
|
|||||||
from fs.memoryfs import MemoryFS
|
from fs.memoryfs import MemoryFS
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
import pytest
|
import pytest
|
||||||
from pytz import utc
|
|
||||||
from xblock.runtime import DictKeyValueStore, KvsFieldData
|
from xblock.runtime import DictKeyValueStore, KvsFieldData
|
||||||
|
|
||||||
from openedx.core.lib.teams_config import TeamsConfig, DEFAULT_COURSE_RUN_MAX_TEAM_SIZE
|
from openedx.core.lib.teams_config import TeamsConfig, DEFAULT_COURSE_RUN_MAX_TEAM_SIZE
|
||||||
@@ -27,9 +27,9 @@ from xmodule.modulestore.exceptions import InvalidProctoringProvider
|
|||||||
ORG = 'test_org'
|
ORG = 'test_org'
|
||||||
COURSE = 'test_course'
|
COURSE = 'test_course'
|
||||||
|
|
||||||
NOW = datetime.strptime('2013-01-01T01:00:00', '%Y-%m-%dT%H:%M:00').replace(tzinfo=utc)
|
NOW = datetime.strptime('2013-01-01T01:00:00', '%Y-%m-%dT%H:%M:00').replace(tzinfo=ZoneInfo("UTC"))
|
||||||
|
|
||||||
_TODAY = datetime.now(utc)
|
_TODAY = datetime.now(ZoneInfo("UTC"))
|
||||||
_LAST_WEEK = _TODAY - timedelta(days=7)
|
_LAST_WEEK = _TODAY - timedelta(days=7)
|
||||||
_NEXT_WEEK = _TODAY + timedelta(days=7)
|
_NEXT_WEEK = _TODAY + timedelta(days=7)
|
||||||
|
|
||||||
|
|||||||
@@ -6,8 +6,8 @@ Tests for course_metadata_utils.
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from unittest import TestCase
|
from unittest import TestCase
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from pytz import utc
|
|
||||||
import pytest
|
import pytest
|
||||||
from xmodule.block_metadata_utils import (
|
from xmodule.block_metadata_utils import (
|
||||||
display_name_with_default,
|
display_name_with_default,
|
||||||
@@ -29,7 +29,7 @@ from xmodule.modulestore.tests.utils import (
|
|||||||
VersioningModulestoreBuilder
|
VersioningModulestoreBuilder
|
||||||
)
|
)
|
||||||
|
|
||||||
_TODAY = datetime.now(utc)
|
_TODAY = datetime.now(ZoneInfo("UTC"))
|
||||||
_LAST_WEEK = _TODAY - timedelta(days=7)
|
_LAST_WEEK = _TODAY - timedelta(days=7)
|
||||||
_NEXT_WEEK = _TODAY + timedelta(days=7)
|
_NEXT_WEEK = _TODAY + timedelta(days=7)
|
||||||
|
|
||||||
@@ -111,7 +111,7 @@ class CourseMetadataUtilsTestCase(TestCase):
|
|||||||
"""Dummy implementation of gettext, so we don't need Django."""
|
"""Dummy implementation of gettext, so we don't need Django."""
|
||||||
return text
|
return text
|
||||||
|
|
||||||
test_datetime = datetime(1945, 2, 6, 4, 20, 00, tzinfo=utc)
|
test_datetime = datetime(1945, 2, 6, 4, 20, 00, tzinfo=ZoneInfo("UTC"))
|
||||||
advertised_start_parsable = "2038-01-19 03:14:07"
|
advertised_start_parsable = "2038-01-19 03:14:07"
|
||||||
|
|
||||||
FunctionTest = namedtuple('FunctionTest', 'function scenarios')
|
FunctionTest = namedtuple('FunctionTest', 'function scenarios')
|
||||||
|
|||||||
@@ -12,10 +12,10 @@ import datetime
|
|||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||||
from pytz import UTC
|
|
||||||
from xblock.exceptions import NotFoundError
|
from xblock.exceptions import NotFoundError
|
||||||
from xblock.field_data import DictFieldData
|
from xblock.field_data import DictFieldData
|
||||||
from xblock.fields import ScopeIds
|
from xblock.fields import ScopeIds
|
||||||
@@ -163,7 +163,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime.now(UTC),
|
last_submission_time=datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=0
|
submission_wait_seconds=0
|
||||||
)
|
)
|
||||||
# Successfully submitted and answered
|
# Successfully submitted and answered
|
||||||
@@ -176,7 +176,7 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime.now(UTC),
|
last_submission_time=datetime.datetime.now(ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=123
|
submission_wait_seconds=123
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait
|
# You should get a dialog that tells you to wait
|
||||||
@@ -189,9 +189,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 18, 36, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 18, 36, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait 2 minutes
|
# You should get a dialog that tells you to wait 2 minutes
|
||||||
# Also, the number of attempts should not be incremented
|
# Also, the number of attempts should not be incremented
|
||||||
@@ -203,9 +203,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 35, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 35, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait 2 minutes
|
# You should get a dialog that tells you to wait 2 minutes
|
||||||
# Also, the number of attempts should not be incremented
|
# Also, the number of attempts should not be incremented
|
||||||
@@ -217,9 +217,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 36, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 20, 36, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# Successfully submitted and answered
|
# Successfully submitted and answered
|
||||||
# Also, the number of attempts should increment by 1
|
# Also, the number of attempts should increment by 1
|
||||||
@@ -231,9 +231,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# Successfully submitted and answered
|
# Successfully submitted and answered
|
||||||
# Also, the number of attempts should increment by 1
|
# Also, the number of attempts should increment by 1
|
||||||
@@ -247,17 +247,17 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
with pytest.raises(NotFoundError):
|
with pytest.raises(NotFoundError):
|
||||||
(block, unused_result) = self.create_and_check(
|
(block, unused_result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Now try it without the submit_problem
|
# Now try it without the submit_problem
|
||||||
(block, unused_result) = self.create_and_check(
|
(block, unused_result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=180,
|
submission_wait_seconds=180,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=UTC),
|
considered_now=datetime.datetime(2013, 12, 6, 0, 24, 0, tzinfo=ZoneInfo("UTC")),
|
||||||
skip_submit_problem=True
|
skip_submit_problem=True
|
||||||
)
|
)
|
||||||
# Expect that number of attempts NOT incremented
|
# Expect that number of attempts NOT incremented
|
||||||
@@ -268,9 +268,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=60 * 60 * 2,
|
submission_wait_seconds=60 * 60 * 2,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 2, 15, 35, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 2, 15, 35, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait 2 minutes
|
# You should get a dialog that tells you to wait 2 minutes
|
||||||
# Also, the number of attempts should not be incremented
|
# Also, the number of attempts should not be incremented
|
||||||
@@ -282,9 +282,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=60 * 60 * 2 + 63,
|
submission_wait_seconds=60 * 60 * 2 + 63,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 1, 15, 40, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 1, 15, 40, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait 2 minutes
|
# You should get a dialog that tells you to wait 2 minutes
|
||||||
# Also, the number of attempts should not be incremented
|
# Also, the number of attempts should not be incremented
|
||||||
@@ -296,9 +296,9 @@ class XModuleQuizAttemptsDelayTest(unittest.TestCase):
|
|||||||
num_attempts = 1
|
num_attempts = 1
|
||||||
(block, result) = self.create_and_check(
|
(block, result) = self.create_and_check(
|
||||||
num_attempts=num_attempts,
|
num_attempts=num_attempts,
|
||||||
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC),
|
last_submission_time=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC")),
|
||||||
submission_wait_seconds=60,
|
submission_wait_seconds=60,
|
||||||
considered_now=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=UTC)
|
considered_now=datetime.datetime(2013, 12, 6, 0, 17, 36, tzinfo=ZoneInfo("UTC"))
|
||||||
)
|
)
|
||||||
# You should get a dialog that tells you to wait 2 minutes
|
# You should get a dialog that tells you to wait 2 minutes
|
||||||
# Also, the number of attempts should not be incremented
|
# Also, the number of attempts should not be incremented
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ from datetime import datetime, timedelta, tzinfo
|
|||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from textwrap import dedent
|
from textwrap import dedent
|
||||||
from unittest import mock
|
from unittest import mock
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
import ddt
|
import ddt
|
||||||
import lxml.etree
|
import lxml.etree
|
||||||
import pytz
|
|
||||||
from django.utils.translation import gettext_lazy
|
from django.utils.translation import gettext_lazy
|
||||||
from fs.osfs import OSFS
|
from fs.osfs import OSFS
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||||
@@ -196,7 +196,7 @@ class TestEdxJsonEncoder(unittest.TestCase):
|
|||||||
assert '2013-05-03T10:20:30' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30))
|
assert '2013-05-03T10:20:30' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30))
|
||||||
|
|
||||||
def test_encode_utc_datetime(self):
|
def test_encode_utc_datetime(self):
|
||||||
assert '2013-05-03T10:20:30+00:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, pytz.UTC))
|
assert '2013-05-03T10:20:30+00:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, ZoneInfo("UTC")))
|
||||||
|
|
||||||
assert '2013-05-03T10:20:30+04:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.offset_tz))
|
assert '2013-05-03T10:20:30+04:00' == self.encoder.default(datetime(2013, 5, 3, 10, 20, 30, 0, self.offset_tz))
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
import datetime
|
import datetime
|
||||||
from tempfile import mkdtemp
|
from tempfile import mkdtemp
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
@@ -11,7 +12,6 @@ from fs.osfs import OSFS
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
from opaque_keys.edx.locator import BlockUsageLocator, CourseLocator
|
||||||
from pytz import UTC
|
|
||||||
from xblock.core import XBlock
|
from xblock.core import XBlock
|
||||||
from xblock.fields import Date, Integer, Scope, String
|
from xblock.fields import Date, Integer, Scope, String
|
||||||
from xblock.runtime import DictKeyValueStore, KvsFieldData
|
from xblock.runtime import DictKeyValueStore, KvsFieldData
|
||||||
@@ -334,7 +334,7 @@ class ImportTestCase(BaseCourseTestCase): # lint-amnesty, pylint: disable=missi
|
|||||||
assert child.due is None
|
assert child.due is None
|
||||||
|
|
||||||
# Check that the child hasn't started yet
|
# Check that the child hasn't started yet
|
||||||
assert datetime.datetime.now(UTC) <= child.start
|
assert datetime.datetime.now(ZoneInfo("UTC")) <= child.start
|
||||||
|
|
||||||
def override_metadata_check(self, block, child, course_due, child_due):
|
def override_metadata_check(self, block, child, course_due, child_due):
|
||||||
"""
|
"""
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ import datetime
|
|||||||
import textwrap
|
import textwrap
|
||||||
import unittest
|
import unittest
|
||||||
from unittest.mock import Mock
|
from unittest.mock import Mock
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
from pytz import UTC
|
|
||||||
from xblock.field_data import DictFieldData
|
from xblock.field_data import DictFieldData
|
||||||
|
|
||||||
from xmodule.lti_2_util import LTIError
|
from xmodule.lti_2_util import LTIError
|
||||||
@@ -380,7 +380,7 @@ class LTI20RESTResultServiceTest(unittest.TestCase):
|
|||||||
Test that we get a 404 when accept_grades_past_due is False and it is past due
|
Test that we get a 404 when accept_grades_past_due is False and it is past due
|
||||||
"""
|
"""
|
||||||
self.setup_system_xblock_mocks_for_lti20_request_test()
|
self.setup_system_xblock_mocks_for_lti20_request_test()
|
||||||
self.xblock.due = datetime.datetime.now(UTC)
|
self.xblock.due = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
self.xblock.accept_grades_past_due = False
|
self.xblock.accept_grades_past_due = False
|
||||||
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
mock_request = self.get_signed_lti20_mock_request(self.GOOD_JSON_PUT)
|
||||||
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
response = self.xblock.lti_2_0_result_rest_handler(mock_request, "user/abcd")
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import textwrap
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from unittest.mock import Mock, PropertyMock, patch
|
from unittest.mock import Mock, PropertyMock, patch
|
||||||
from urllib import parse
|
from urllib import parse
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -14,7 +15,6 @@ from django.test import TestCase, override_settings
|
|||||||
from lxml import etree
|
from lxml import etree
|
||||||
from opaque_keys.edx.keys import CourseKey
|
from opaque_keys.edx.keys import CourseKey
|
||||||
from opaque_keys.edx.locator import BlockUsageLocator
|
from opaque_keys.edx.locator import BlockUsageLocator
|
||||||
from pytz import UTC
|
|
||||||
from webob.request import Request
|
from webob.request import Request
|
||||||
from xblock.field_data import DictFieldData
|
from xblock.field_data import DictFieldData
|
||||||
from xblock.fields import ScopeIds, Timedelta
|
from xblock.fields import ScopeIds, Timedelta
|
||||||
@@ -198,7 +198,7 @@ class LTIBlockTest(TestCase):
|
|||||||
Should fail if we do not accept past due grades, and it is past due.
|
Should fail if we do not accept past due grades, and it is past due.
|
||||||
"""
|
"""
|
||||||
self.xblock.accept_grades_past_due = False
|
self.xblock.accept_grades_past_due = False
|
||||||
self.xblock.due = datetime.datetime.now(UTC)
|
self.xblock.due = datetime.datetime.now(ZoneInfo("UTC"))
|
||||||
self.xblock.graceperiod = Timedelta().from_json("0 seconds")
|
self.xblock.graceperiod = Timedelta().from_json("0 seconds")
|
||||||
request = Request(self.environ)
|
request = Request(self.environ)
|
||||||
request.body = self.get_request_body()
|
request.body = self.get_request_body()
|
||||||
|
|||||||
@@ -9,9 +9,9 @@ import json
|
|||||||
from collections import namedtuple
|
from collections import namedtuple
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from unittest.mock import Mock, patch
|
from unittest.mock import Mock, patch
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
import pytz
|
|
||||||
from django.contrib.auth.models import AnonymousUser
|
from django.contrib.auth.models import AnonymousUser
|
||||||
from django.test import override_settings
|
from django.test import override_settings
|
||||||
from fs.memoryfs import MemoryFS
|
from fs.memoryfs import MemoryFS
|
||||||
@@ -213,7 +213,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
|||||||
Test the rendering of the student and public view.
|
Test the rendering of the student and public view.
|
||||||
"""
|
"""
|
||||||
self.course.runtime._services['bookmarks'] = Mock()
|
self.course.runtime._services['bookmarks'] = Mock()
|
||||||
now = datetime.now(pytz.UTC)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
self.vertical.due = now + timedelta(days=days)
|
self.vertical.due = now + timedelta(days=days)
|
||||||
if view == STUDENT_VIEW:
|
if view == STUDENT_VIEW:
|
||||||
self.course.runtime._services['user'] = StubUserService(user=Mock(username=self.username))
|
self.course.runtime._services['user'] = StubUserService(user=Mock(username=self.username))
|
||||||
@@ -253,7 +253,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
|||||||
self.course.runtime._services['user'] = StubUserService(user=Mock())
|
self.course.runtime._services['user'] = StubUserService(user=Mock())
|
||||||
self.course.runtime._services['completion'] = StubCompletionService(enabled=True, completion_value=0)
|
self.course.runtime._services['completion'] = StubCompletionService(enabled=True, completion_value=0)
|
||||||
|
|
||||||
now = datetime.now(pytz.UTC)
|
now = datetime.now(ZoneInfo("UTC"))
|
||||||
self.vertical.due = now + timedelta(days=-1)
|
self.vertical.due = now + timedelta(days=-1)
|
||||||
self.problem_block.has_score = has_score
|
self.problem_block.has_score = has_score
|
||||||
|
|
||||||
@@ -273,7 +273,7 @@ class VerticalBlockTestCase(BaseVerticalBlockTest):
|
|||||||
""" Tests access denied blocks are not rendered when hide_access_error_blocks is True """
|
""" Tests access denied blocks are not rendered when hide_access_error_blocks is True """
|
||||||
self.course.runtime._services['bookmarks'] = Mock()
|
self.course.runtime._services['bookmarks'] = Mock()
|
||||||
self.course.runtime._services['user'] = StubUserService(user=Mock())
|
self.course.runtime._services['user'] = StubUserService(user=Mock())
|
||||||
self.vertical.due = datetime.now(pytz.UTC) + timedelta(days=-1)
|
self.vertical.due = datetime.now(ZoneInfo("UTC")) + timedelta(days=-1)
|
||||||
self.problem_block.has_access_error = node_has_access_error
|
self.problem_block.has_access_error = node_has_access_error
|
||||||
self.nested_problem_block.has_access_error = child_has_access_error
|
self.nested_problem_block.has_access_error = child_has_access_error
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ import logging
|
|||||||
from copy import copy
|
from copy import copy
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from functools import reduce
|
from functools import reduce
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pytz
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from lxml import etree
|
from lxml import etree
|
||||||
from openedx_filters.learning.filters import VerticalBlockChildRenderStarted, VerticalBlockRenderCompleted
|
from openedx_filters.learning.filters import VerticalBlockChildRenderStarted, VerticalBlockRenderCompleted
|
||||||
@@ -137,7 +137,7 @@ class VerticalBlock(
|
|||||||
})
|
})
|
||||||
|
|
||||||
completed = self.is_block_complete_for_assignments(completion_service)
|
completed = self.is_block_complete_for_assignments(completion_service)
|
||||||
past_due = completed is False and self.due and self.due < datetime.now(pytz.UTC)
|
past_due = completed is False and self.due and self.due < datetime.now(ZoneInfo("UTC"))
|
||||||
cta_service = self.runtime.service(self, 'call_to_action')
|
cta_service = self.runtime.service(self, 'call_to_action')
|
||||||
vertical_banner_ctas = cta_service.get_ctas(self, 'vertical_banner', completed) if cta_service else []
|
vertical_banner_ctas = cta_service.get_ctas(self, 'vertical_banner', completed) if cta_service else []
|
||||||
|
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from collections import OrderedDict
|
from collections import OrderedDict
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
|
from zoneinfo import ZoneInfo
|
||||||
|
|
||||||
import pytz
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
|
|
||||||
from .video_utils import set_query_parameter
|
from .video_utils import set_query_parameter
|
||||||
@@ -48,7 +48,7 @@ def is_bumper_enabled(video):
|
|||||||
bool.
|
bool.
|
||||||
"""
|
"""
|
||||||
bumper_last_view_date = getattr(video, 'bumper_last_view_date', None)
|
bumper_last_view_date = getattr(video, 'bumper_last_view_date', None)
|
||||||
utc_now = datetime.utcnow().replace(tzinfo=pytz.utc)
|
utc_now = datetime.now(ZoneInfo("UTC"))
|
||||||
periodicity = settings.FEATURES.get('SHOW_BUMPER_PERIODICITY', 0)
|
periodicity = settings.FEATURES.get('SHOW_BUMPER_PERIODICITY', 0)
|
||||||
has_viewed = any([
|
has_viewed = any([
|
||||||
video.bumper_do_not_show_again,
|
video.bumper_do_not_show_again,
|
||||||
|
|||||||
Reference in New Issue
Block a user