diff --git a/cms/djangoapps/contentstore/tests/test_contentstore.py b/cms/djangoapps/contentstore/tests/test_contentstore.py
index 232b68ecc8..1e6ab8cd86 100644
--- a/cms/djangoapps/contentstore/tests/test_contentstore.py
+++ b/cms/djangoapps/contentstore/tests/test_contentstore.py
@@ -271,7 +271,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
)
self.assertTrue(getattr(draft_problem, 'is_draft', False))
- #now requery with depth
+ # now requery with depth
course = modulestore('draft').get_item(
Location(['i4x', 'edX', 'simple', 'course', '2012_Fall', None]),
depth=None
@@ -539,7 +539,7 @@ class ContentStoreToyCourseTest(ModuleStoreTestCase):
on_disk = loads(grading_policy.read())
self.assertEqual(on_disk, course.grading_policy)
- #check for policy.json
+ # check for policy.json
self.assertTrue(filesystem.exists('policy.json'))
# compare what's on disk to what we have in the course module
@@ -990,7 +990,7 @@ class ContentStoreTest(ModuleStoreTestCase):
def test_metadata_inheritance(self):
module_store = modulestore('direct')
- import_from_xml(module_store, 'common/test/data/', ['full'])
+ import_from_xml(module_store, 'common/test/data/', ['full'], verbose=True)
course = module_store.get_item(Location(['i4x', 'edX', 'full', 'course', '6.002_Spring_2012', None]))
diff --git a/cms/djangoapps/contentstore/tests/test_course_settings.py b/cms/djangoapps/contentstore/tests/test_course_settings.py
index 2a4ff46038..c1b7a9fa0e 100644
--- a/cms/djangoapps/contentstore/tests/test_course_settings.py
+++ b/cms/djangoapps/contentstore/tests/test_course_settings.py
@@ -151,22 +151,16 @@ class CourseDetailsViewTest(CourseTestCase):
self.assertEqual(details['intro_video'], encoded.get('intro_video', None), context + " intro_video not ==")
self.assertEqual(details['effort'], encoded['effort'], context + " efforts not ==")
- @staticmethod
- def struct_to_datetime(struct_time):
- return datetime.datetime(*struct_time[:6], tzinfo=UTC())
-
def compare_date_fields(self, details, encoded, context, field):
if details[field] is not None:
date = Date()
if field in encoded and encoded[field] is not None:
- encoded_encoded = date.from_json(encoded[field])
- dt1 = CourseDetailsViewTest.struct_to_datetime(encoded_encoded)
+ dt1 = date.from_json(encoded[field])
if isinstance(details[field], datetime.datetime):
dt2 = details[field]
else:
- details_encoded = date.from_json(details[field])
- dt2 = CourseDetailsViewTest.struct_to_datetime(details_encoded)
+ dt2 = date.from_json(details[field])
expected_delta = datetime.timedelta(0)
self.assertEqual(dt1 - dt2, expected_delta, str(dt1) + "!=" + str(dt2) + " at " + context)
diff --git a/cms/djangoapps/contentstore/views/assets.py b/cms/djangoapps/contentstore/views/assets.py
index b5041d3e9f..2be2cfafb8 100644
--- a/cms/djangoapps/contentstore/views/assets.py
+++ b/cms/djangoapps/contentstore/views/assets.py
@@ -62,7 +62,7 @@ def asset_index(request, org, course, name):
asset_id = asset['_id']
display_info = {}
display_info['displayname'] = asset['displayname']
- display_info['uploadDate'] = get_default_time_display(asset['uploadDate'].timetuple())
+ display_info['uploadDate'] = get_default_time_display(asset['uploadDate'])
asset_location = StaticContent.compute_location(asset_id['org'], asset_id['course'], asset_id['name'])
display_info['url'] = StaticContent.get_url_path_from_location(asset_location)
@@ -131,7 +131,7 @@ def upload_asset(request, org, course, coursename):
readback = contentstore().find(content.location)
response_payload = {'displayname': content.name,
- 'uploadDate': get_default_time_display(readback.last_modified_at.timetuple()),
+ 'uploadDate': get_default_time_display(readback.last_modified_at),
'url': StaticContent.get_url_path_from_location(content.location),
'thumb_url': StaticContent.get_url_path_from_location(thumbnail_location) if thumbnail_content is not None else None,
'msg': 'Upload completed'
@@ -231,7 +231,7 @@ def generate_export_course(request, org, course, name):
logging.debug('root = {0}'.format(root_dir))
export_to_xml(modulestore('direct'), contentstore(), loc, root_dir, name, modulestore())
- #filename = root_dir / name + '.tar.gz'
+ # filename = root_dir / name + '.tar.gz'
logging.debug('tar file being generated at {0}'.format(export_file.name))
tar_file = tarfile.open(name=export_file.name, mode='w:gz')
diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py
index 07f6b9669c..e1c176eebe 100644
--- a/cms/djangoapps/contentstore/views/course.py
+++ b/cms/djangoapps/contentstore/views/course.py
@@ -2,7 +2,6 @@
Views related to operations on course objects
"""
import json
-import time
from django.contrib.auth.decorators import login_required
from django_future.csrf import ensure_csrf_cookie
@@ -32,6 +31,8 @@ from .component import OPEN_ENDED_COMPONENT_TYPES, \
NOTE_COMPONENT_TYPES, ADVANCED_COMPONENT_POLICY_KEY
from django_comment_common.utils import seed_permissions_roles
+import datetime
+from django.utils.timezone import UTC
# TODO: should explicitly enumerate exports with __all__
@@ -130,7 +131,7 @@ def create_new_course(request):
new_course.display_name = display_name
# set a default start date to now
- new_course.start = time.gmtime()
+ new_course.start = datetime.datetime.now(UTC())
initialize_course_tabs(new_course)
@@ -357,49 +358,49 @@ def course_advanced_updates(request, org, course, name):
# Whether or not to filter the tabs key out of the settings metadata
filter_tabs = True
- #Check to see if the user instantiated any advanced components. This is a hack
- #that does the following :
- # 1) adds/removes the open ended panel tab to a course automatically if the user
+ # Check to see if the user instantiated any advanced components. This is a hack
+ # that does the following :
+ # 1) adds/removes the open ended panel tab to a course automatically if the user
# has indicated that they want to edit the combinedopendended or peergrading module
# 2) adds/removes the notes panel tab to a course automatically if the user has
# indicated that they want the notes module enabled in their course
# TODO refactor the above into distinct advanced policy settings
if ADVANCED_COMPONENT_POLICY_KEY in request_body:
- #Get the course so that we can scrape current tabs
+ # Get the course so that we can scrape current tabs
course_module = modulestore().get_item(location)
- #Maps tab types to components
+ # Maps tab types to components
tab_component_map = {
- 'open_ended': OPEN_ENDED_COMPONENT_TYPES,
+ 'open_ended': OPEN_ENDED_COMPONENT_TYPES,
'notes': NOTE_COMPONENT_TYPES,
}
- #Check to see if the user instantiated any notes or open ended components
+ # Check to see if the user instantiated any notes or open ended components
for tab_type in tab_component_map.keys():
component_types = tab_component_map.get(tab_type)
found_ac_type = False
for ac_type in component_types:
if ac_type in request_body[ADVANCED_COMPONENT_POLICY_KEY]:
- #Add tab to the course if needed
+ # Add tab to the course if needed
changed, new_tabs = add_extra_panel_tab(tab_type, course_module)
- #If a tab has been added to the course, then send the metadata along to CourseMetadata.update_from_json
+ # If a tab has been added to the course, then send the metadata along to CourseMetadata.update_from_json
if changed:
course_module.tabs = new_tabs
request_body.update({'tabs': new_tabs})
- #Indicate that tabs should not be filtered out of the metadata
+ # Indicate that tabs should not be filtered out of the metadata
filter_tabs = False
- #Set this flag to avoid the tab removal code below.
+ # Set this flag to avoid the tab removal code below.
found_ac_type = True
break
- #If we did not find a module type in the advanced settings,
+ # If we did not find a module type in the advanced settings,
# we may need to remove the tab from the course.
if not found_ac_type:
- #Remove tab from the course if needed
+ # Remove tab from the course if needed
changed, new_tabs = remove_extra_panel_tab(tab_type, course_module)
if changed:
course_module.tabs = new_tabs
request_body.update({'tabs': new_tabs})
- #Indicate that tabs should *not* be filtered out of the metadata
+ # Indicate that tabs should *not* be filtered out of the metadata
filter_tabs = False
response_json = json.dumps(CourseMetadata.update_from_json(location,
diff --git a/cms/djangoapps/models/settings/course_details.py b/cms/djangoapps/models/settings/course_details.py
index 0dbb47b31b..28dba473f2 100644
--- a/cms/djangoapps/models/settings/course_details.py
+++ b/cms/djangoapps/models/settings/course_details.py
@@ -3,26 +3,26 @@ from xmodule.modulestore.exceptions import ItemNotFoundError
from xmodule.modulestore.inheritance import own_metadata
import json
from json.encoder import JSONEncoder
-import time
from contentstore.utils import get_modulestore
from models.settings import course_grading
from contentstore.utils import update_item
from xmodule.fields import Date
import re
import logging
+import datetime
class CourseDetails(object):
def __init__(self, location):
- self.course_location = location # a Location obj
+ self.course_location = location # a Location obj
self.start_date = None # 'start'
- self.end_date = None # 'end'
+ self.end_date = None # 'end'
self.enrollment_start = None
self.enrollment_end = None
- self.syllabus = None # a pdf file asset
- self.overview = "" # html to render as the overview
- self.intro_video = None # a video pointer
- self.effort = None # int hours/week
+ self.syllabus = None # a pdf file asset
+ self.overview = "" # html to render as the overview
+ self.intro_video = None # a video pointer
+ self.effort = None # int hours/week
@classmethod
def fetch(cls, course_location):
@@ -73,9 +73,9 @@ class CourseDetails(object):
"""
Decode the json into CourseDetails and save any changed attrs to the db
"""
- ## TODO make it an error for this to be undefined & for it to not be retrievable from modulestore
+ # # TODO make it an error for this to be undefined & for it to not be retrievable from modulestore
course_location = jsondict['course_location']
- ## Will probably want to cache the inflight courses because every blur generates an update
+ # # Will probably want to cache the inflight courses because every blur generates an update
descriptor = get_modulestore(course_location).get_item(course_location)
dirty = False
@@ -181,7 +181,7 @@ class CourseSettingsEncoder(json.JSONEncoder):
return obj.__dict__
elif isinstance(obj, Location):
return obj.dict()
- elif isinstance(obj, time.struct_time):
+ elif isinstance(obj, datetime.datetime):
return Date().to_json(obj)
else:
return JSONEncoder.default(self, obj)
diff --git a/cms/templates/edit_subsection.html b/cms/templates/edit_subsection.html
index 9bb9b3a506..4aae070ca1 100644
--- a/cms/templates/edit_subsection.html
+++ b/cms/templates/edit_subsection.html
@@ -1,7 +1,7 @@
<%inherit file="base.html" />
<%!
import logging
- from xmodule.util.date_utils import get_time_struct_display
+ from xmodule.util.date_utils import get_default_time_display
%>
<%! from django.core.urlresolvers import reverse %>
@@ -36,11 +36,15 @@
% if subsection.lms.start != parent_item.lms.start and subsection.lms.start:
@@ -48,7 +52,7 @@
The date above differs from the release date of ${parent_item.display_name_with_default}, which is unset.
% else:
The date above differs from the release date of ${parent_item.display_name_with_default} –
- ${get_time_struct_display(parent_item.lms.start, '%m/%d/%Y at %H:%M UTC')}.
+ ${get_default_time_display(parent_item.lms.start)}.
% endif
Sync to ${parent_item.display_name_with_default}.
% endif
@@ -65,11 +69,15 @@
diff --git a/cms/templates/overview.html b/cms/templates/overview.html
index d327c8b324..0b82d76943 100644
--- a/cms/templates/overview.html
+++ b/cms/templates/overview.html
@@ -1,7 +1,7 @@
<%inherit file="base.html" />
<%!
import logging
- from xmodule.util.date_utils import get_time_struct_display
+ from xmodule.util import date_utils
%>
<%! from django.core.urlresolvers import reverse %>
<%block name="title">Course Outline%block>
@@ -154,14 +154,15 @@
<%
- start_date_str = get_time_struct_display(section.lms.start, '%m/%d/%Y')
- start_time_str = get_time_struct_display(section.lms.start, '%H:%M')
+ start_date_str = section.lms.start.strftime('%m/%d/%Y')
+ start_time_str = section.lms.start.strftime('%H:%M')
%>
%if section.lms.start is None:
This section has not been released.
Schedule
%else:
-
Will Release: ${get_time_struct_display(section.lms.start, '%m/%d/%Y at %H:%M UTC')}
+
Will Release:
+ ${date_utils.get_default_time_display(section.lms.start)}
Edit
%endif
diff --git a/common/djangoapps/contentserver/middleware.py b/common/djangoapps/contentserver/middleware.py
index 8e9e70046d..7deb0901aa 100644
--- a/common/djangoapps/contentserver/middleware.py
+++ b/common/djangoapps/contentserver/middleware.py
@@ -1,7 +1,4 @@
-import logging
-import time
-
-from django.http import HttpResponse, Http404, HttpResponseNotModified
+from django.http import HttpResponse, HttpResponseNotModified
from xmodule.contentstore.django import contentstore
from xmodule.contentstore.content import StaticContent, XASSET_LOCATION_TAG
@@ -20,7 +17,7 @@ class StaticContentServer(object):
# return a 'Bad Request' to browser as we have a malformed Location
response = HttpResponse()
response.status_code = 400
- return response
+ return response
# first look in our cache so we don't have to round-trip to the DB
content = get_cached_content(loc)
diff --git a/common/djangoapps/student/management/commands/pearson_make_tc_registration.py b/common/djangoapps/student/management/commands/pearson_make_tc_registration.py
index b10cf143a0..50e56bb4be 100644
--- a/common/djangoapps/student/management/commands/pearson_make_tc_registration.py
+++ b/common/djangoapps/student/management/commands/pearson_make_tc_registration.py
@@ -1,5 +1,4 @@
from optparse import make_option
-from time import strftime
from django.contrib.auth.models import User
from django.core.management.base import BaseCommand, CommandError
@@ -128,8 +127,8 @@ class Command(BaseCommand):
exam = CourseDescriptor.TestCenterExam(course_id, exam_name, exam_info)
# update option values for date_first and date_last to use YYYY-MM-DD format
# instead of YYYY-MM-DDTHH:MM
- our_options['eligibility_appointment_date_first'] = strftime("%Y-%m-%d", exam.first_eligible_appointment_date)
- our_options['eligibility_appointment_date_last'] = strftime("%Y-%m-%d", exam.last_eligible_appointment_date)
+ our_options['eligibility_appointment_date_first'] = exam.first_eligible_appointment_date.strftime("%Y-%m-%d")
+ our_options['eligibility_appointment_date_last'] = exam.last_eligible_appointment_date.strftime("%Y-%m-%d")
if exam is None:
raise CommandError("Exam for course_id {} does not exist".format(course_id))
diff --git a/common/djangoapps/student/models.py b/common/djangoapps/student/models.py
index ab68b05f4b..57f3d756b9 100644
--- a/common/djangoapps/student/models.py
+++ b/common/djangoapps/student/models.py
@@ -16,7 +16,6 @@ import json
import logging
import uuid
from random import randint
-from time import strftime
from django.conf import settings
@@ -54,7 +53,7 @@ class UserProfile(models.Model):
class Meta:
db_table = "auth_userprofile"
- ## CRITICAL TODO/SECURITY
+ # # CRITICAL TODO/SECURITY
# Sanitize all fields.
# This is not visible to other users, but could introduce holes later
user = models.OneToOneField(User, unique=True, db_index=True, related_name='profile')
@@ -429,8 +428,8 @@ class TestCenterRegistration(models.Model):
registration.course_id = exam.course_id
registration.accommodation_request = accommodation_request.strip()
registration.exam_series_code = exam.exam_series_code
- registration.eligibility_appointment_date_first = strftime("%Y-%m-%d", exam.first_eligible_appointment_date)
- registration.eligibility_appointment_date_last = strftime("%Y-%m-%d", exam.last_eligible_appointment_date)
+ registration.eligibility_appointment_date_first = exam.first_eligible_appointment_date.strftime("%Y-%m-%d")
+ registration.eligibility_appointment_date_last = exam.last_eligible_appointment_date.strftime("%Y-%m-%d")
registration.client_authorization_id = cls._create_client_authorization_id()
# accommodation_code remains blank for now, along with Pearson confirmation information
return registration
@@ -598,7 +597,7 @@ def unique_id_for_user(user):
return h.hexdigest()
-## TODO: Should be renamed to generic UserGroup, and possibly
+# # TODO: Should be renamed to generic UserGroup, and possibly
# Given an optional field for type of group
class UserTestGroup(models.Model):
users = models.ManyToManyField(User, db_index=True)
@@ -626,7 +625,7 @@ class Registration(models.Model):
def activate(self):
self.user.is_active = True
self.user.save()
- #self.delete()
+ # self.delete()
class PendingNameChange(models.Model):
@@ -648,7 +647,7 @@ class CourseEnrollment(models.Model):
created = models.DateTimeField(auto_now_add=True, null=True, db_index=True)
class Meta:
- unique_together = (('user', 'course_id'), )
+ unique_together = (('user', 'course_id'),)
def __unicode__(self):
return "[CourseEnrollment] %s: %s (%s)" % (self.user, self.course_id, self.created)
@@ -667,12 +666,12 @@ class CourseEnrollmentAllowed(models.Model):
created = models.DateTimeField(auto_now_add=True, null=True, db_index=True)
class Meta:
- unique_together = (('email', 'course_id'), )
+ unique_together = (('email', 'course_id'),)
def __unicode__(self):
return "[CourseEnrollmentAllowed] %s: %s (%s)" % (self.email, self.course_id, self.created)
-#cache_relation(User.profile)
+# cache_relation(User.profile)
#### Helper methods for use from python manage.py shell and other classes.
diff --git a/common/djangoapps/xmodule_modifiers.py b/common/djangoapps/xmodule_modifiers.py
index 45691cd854..570b38c942 100644
--- a/common/djangoapps/xmodule_modifiers.py
+++ b/common/djangoapps/xmodule_modifiers.py
@@ -1,7 +1,6 @@
import re
import json
import logging
-import time
import static_replace
from django.conf import settings
@@ -9,6 +8,8 @@ from functools import wraps
from mitxmako.shortcuts import render_to_string
from xmodule.seq_module import SequenceModule
from xmodule.vertical_module import VerticalModule
+import datetime
+from django.utils.timezone import UTC
log = logging.getLogger("mitx.xmodule_modifiers")
@@ -83,7 +84,7 @@ def grade_histogram(module_id):
cursor.execute(q, [module_id])
grades = list(cursor.fetchall())
- grades.sort(key=lambda x: x[0]) # Add ORDER BY to sql query?
+ grades.sort(key=lambda x: x[0]) # Add ORDER BY to sql query?
if len(grades) >= 1 and grades[0][0] is None:
return []
return grades
@@ -101,7 +102,7 @@ def add_histogram(get_html, module, user):
@wraps(get_html)
def _get_html():
- if type(module) in [SequenceModule, VerticalModule]: # TODO: make this more general, eg use an XModule attribute instead
+ if type(module) in [SequenceModule, VerticalModule]: # TODO: make this more general, eg use an XModule attribute instead
return get_html()
module_id = module.id
@@ -132,7 +133,7 @@ def add_histogram(get_html, module, user):
# useful to indicate to staff if problem has been released or not
# TODO (ichuang): use _has_access_descriptor.can_load in lms.courseware.access, instead of now>mstart comparison here
- now = time.gmtime()
+ now = datetime.datetime.now(UTC())
is_released = "unknown"
mstart = module.descriptor.lms.start
diff --git a/common/lib/capa/capa/inputtypes.py b/common/lib/capa/capa/inputtypes.py
index 65280d6d29..3680379406 100644
--- a/common/lib/capa/capa/inputtypes.py
+++ b/common/lib/capa/capa/inputtypes.py
@@ -144,11 +144,11 @@ class InputTypeBase(object):
self.tag = xml.tag
self.system = system
- ## NOTE: ID should only come from one place. If it comes from multiple,
- ## we use state first, XML second (in case the xml changed, but we have
- ## existing state with an old id). Since we don't make this guarantee,
- ## we can swap this around in the future if there's a more logical
- ## order.
+ # # NOTE: ID should only come from one place. If it comes from multiple,
+ # # we use state first, XML second (in case the xml changed, but we have
+ # # existing state with an old id). Since we don't make this guarantee,
+ # # we can swap this around in the future if there's a more logical
+ # # order.
self.input_id = state.get('id', xml.get('id'))
if self.input_id is None:
@@ -769,7 +769,7 @@ class MatlabInput(CodeInput):
# construct xqueue headers
qinterface = self.system.xqueue['interface']
- qtime = datetime.strftime(datetime.utcnow(), xqueue_interface.dateformat)
+ qtime = datetime.utcnow().strftime(xqueue_interface.dateformat)
callback_url = self.system.xqueue['construct_callback']('ungraded_response')
anonymous_student_id = self.system.anonymous_student_id
queuekey = xqueue_interface.make_hashkey(str(self.system.seed) + qtime +
diff --git a/common/lib/xmodule/xmodule/capa_module.py b/common/lib/xmodule/xmodule/capa_module.py
index 9e0ab16203..51b20c12ea 100644
--- a/common/lib/xmodule/xmodule/capa_module.py
+++ b/common/lib/xmodule/xmodule/capa_module.py
@@ -11,7 +11,7 @@ import sys
from pkg_resources import resource_string
from capa.capa_problem import LoncapaProblem
-from capa.responsetypes import StudentInputError,\
+from capa.responsetypes import StudentInputError, \
ResponseError, LoncapaProblemError
from capa.util import convert_files_to_filenames
from .progress import Progress
@@ -20,7 +20,7 @@ from xmodule.raw_module import RawDescriptor
from xmodule.exceptions import NotFoundError, ProcessingError
from xblock.core import Scope, String, Boolean, Object
from .fields import Timedelta, Date, StringyInteger, StringyFloat
-from xmodule.util.date_utils import time_to_datetime
+from django.utils.timezone import UTC
log = logging.getLogger("mitx.courseware")
@@ -134,7 +134,7 @@ class CapaModule(CapaFields, XModule):
def __init__(self, system, location, descriptor, model_data):
XModule.__init__(self, system, location, descriptor, model_data)
- due_date = time_to_datetime(self.due)
+ due_date = self.due
if self.graceperiod is not None and due_date:
self.close_date = due_date + self.graceperiod
@@ -502,7 +502,7 @@ class CapaModule(CapaFields, XModule):
Is it now past this problem's due date, including grace period?
"""
return (self.close_date is not None and
- datetime.datetime.utcnow() > self.close_date)
+ datetime.datetime.now(UTC()) > self.close_date)
def closed(self):
''' Is the student still allowed to submit answers? '''
diff --git a/common/lib/xmodule/xmodule/course_module.py b/common/lib/xmodule/xmodule/course_module.py
index 063e53aef4..66d53b43ec 100644
--- a/common/lib/xmodule/xmodule/course_module.py
+++ b/common/lib/xmodule/xmodule/course_module.py
@@ -4,7 +4,6 @@ from math import exp
from lxml import etree
from path import path # NOTE (THK): Only used for detecting presence of syllabus
import requests
-import time
from datetime import datetime
import dateutil.parser
@@ -14,11 +13,11 @@ from xmodule.seq_module import SequenceDescriptor, SequenceModule
from xmodule.timeparse import parse_time
from xmodule.util.decorators import lazyproperty
from xmodule.graders import grader_from_conf
-from xmodule.util.date_utils import time_to_datetime
import json
from xblock.core import Scope, List, String, Object, Boolean
from .fields import Date
+from django.utils.timezone import UTC
log = logging.getLogger(__name__)
@@ -219,8 +218,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
msg = None
if self.start is None:
msg = "Course loaded without a valid start date. id = %s" % self.id
- # hack it -- start in 1970
- self.start = time.gmtime(0)
+ self.start = datetime.now(UTC())
log.critical(msg)
self.system.error_tracker(msg)
@@ -392,7 +390,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
textbook_xml_object.set('book_url', textbook.book_url)
xml_object.append(textbook_xml_object)
-
+
return xml_object
def has_ended(self):
@@ -403,10 +401,10 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
if self.end is None:
return False
- return time.gmtime() > self.end
+ return datetime.now(UTC()) > self.end
def has_started(self):
- return time.gmtime() > self.start
+ return datetime.now(UTC()) > self.start
@property
def grader(self):
@@ -547,14 +545,16 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
announcement = self.announcement
if announcement is not None:
- announcement = time_to_datetime(announcement)
+ announcement = announcement
try:
start = dateutil.parser.parse(self.advertised_start)
+ if start.tzinfo is None:
+ start = start.replace(tzinfo=UTC())
except (ValueError, AttributeError):
- start = time_to_datetime(self.start)
+ start = self.start
- now = datetime.utcnow()
+ now = datetime.now(UTC())
return announcement, start, now
@@ -656,7 +656,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
elif self.advertised_start is None and self.start is None:
return 'TBD'
else:
- return time.strftime("%b %d, %Y", self.advertised_start or self.start)
+ return (self.advertised_start or self.start).strftime("%b %d, %Y")
@property
def end_date_text(self):
@@ -665,7 +665,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
If the course does not have an end date set (course.end is None), an empty string will be returned.
"""
- return '' if self.end is None else time.strftime("%b %d, %Y", self.end)
+ return '' if self.end is None else self.end.strftime("%b %d, %Y")
@property
def forum_posts_allowed(self):
@@ -673,7 +673,7 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
blackout_periods = [(parse_time(start), parse_time(end))
for start, end
in self.discussion_blackouts]
- now = time.gmtime()
+ now = datetime.now(UTC())
for start, end in blackout_periods:
if start <= now <= end:
return False
@@ -699,7 +699,8 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
self.last_eligible_appointment_date = self._try_parse_time('Last_Eligible_Appointment_Date') # or self.first_eligible_appointment_date
if self.last_eligible_appointment_date is None:
raise ValueError("Last appointment date must be specified")
- self.registration_start_date = self._try_parse_time('Registration_Start_Date') or time.gmtime(0)
+ self.registration_start_date = (self._try_parse_time('Registration_Start_Date') or
+ datetime.utcfromtimestamp(0))
self.registration_end_date = self._try_parse_time('Registration_End_Date') or self.last_eligible_appointment_date
# do validation within the exam info:
if self.registration_start_date > self.registration_end_date:
@@ -725,32 +726,32 @@ class CourseDescriptor(CourseFields, SequenceDescriptor):
return None
def has_started(self):
- return time.gmtime() > self.first_eligible_appointment_date
+ return datetime.now(UTC()) > self.first_eligible_appointment_date
def has_ended(self):
- return time.gmtime() > self.last_eligible_appointment_date
+ return datetime.now(UTC()) > self.last_eligible_appointment_date
def has_started_registration(self):
- return time.gmtime() > self.registration_start_date
+ return datetime.now(UTC()) > self.registration_start_date
def has_ended_registration(self):
- return time.gmtime() > self.registration_end_date
+ return datetime.now(UTC()) > self.registration_end_date
def is_registering(self):
- now = time.gmtime()
+ now = datetime.now(UTC())
return now >= self.registration_start_date and now <= self.registration_end_date
@property
def first_eligible_appointment_date_text(self):
- return time.strftime("%b %d, %Y", self.first_eligible_appointment_date)
+ return datetime.strftime("%b %d, %Y", self.first_eligible_appointment_date)
@property
def last_eligible_appointment_date_text(self):
- return time.strftime("%b %d, %Y", self.last_eligible_appointment_date)
+ return datetime.strftime("%b %d, %Y", self.last_eligible_appointment_date)
@property
def registration_end_date_text(self):
- return time.strftime("%b %d, %Y at %H:%M UTC", self.registration_end_date)
+ return datetime.strftime("%b %d, %Y at %H:%M UTC", self.registration_end_date)
@property
def current_test_center_exam(self):
diff --git a/common/lib/xmodule/xmodule/fields.py b/common/lib/xmodule/xmodule/fields.py
index 3d56b7941e..3164c062bb 100644
--- a/common/lib/xmodule/xmodule/fields.py
+++ b/common/lib/xmodule/xmodule/fields.py
@@ -2,19 +2,19 @@ import time
import logging
import re
-from datetime import timedelta
from xblock.core import ModelType
import datetime
import dateutil.parser
from xblock.core import Integer, Float, Boolean
+from django.utils.timezone import UTC
log = logging.getLogger(__name__)
class Date(ModelType):
'''
- Date fields know how to parse and produce json (iso) compatible formats.
+ Date fields know how to parse and produce json (iso) compatible formats. Converts to tz aware datetimes.
'''
def from_json(self, field):
"""
@@ -27,11 +27,15 @@ class Date(ModelType):
elif field is "":
return None
elif isinstance(field, basestring):
- d = dateutil.parser.parse(field)
- return d.utctimetuple()
+ result = dateutil.parser.parse(field)
+ if result.tzinfo is None:
+ result = result.replace(tzinfo=UTC())
+ return result
elif isinstance(field, (int, long, float)):
- return time.gmtime(field / 1000)
+ return datetime.datetime.fromtimestamp(field / 1000, UTC())
elif isinstance(field, time.struct_time):
+ return datetime.datetime.fromtimestamp(time.mktime(field), UTC())
+ elif isinstance(field, datetime.datetime):
return field
else:
msg = "Field {0} has bad value '{1}'".format(
@@ -49,7 +53,11 @@ class Date(ModelType):
# struct_times are always utc
return time.strftime('%Y-%m-%dT%H:%M:%SZ', value)
elif isinstance(value, datetime.datetime):
- return value.isoformat() + 'Z'
+ if value.tzinfo is None or value.utcoffset().total_seconds() == 0:
+ # isoformat adds +00:00 rather than Z
+ return value.strftime('%Y-%m-%dT%H:%M:%SZ')
+ else:
+ return value.isoformat()
TIMEDELTA_REGEX = re.compile(r'^((?P\d+?) day(?:s?))?(\s)?((?P\d+?) hour(?:s?))?(\s)?((?P\d+?) minute(?:s)?)?(\s)?((?P\d+?) second(?:s)?)?$')
@@ -74,7 +82,7 @@ class Timedelta(ModelType):
for (name, param) in parts.iteritems():
if param:
time_params[name] = int(param)
- return timedelta(**time_params)
+ return datetime.timedelta(**time_params)
def to_json(self, value):
values = []
@@ -93,7 +101,7 @@ class StringyInteger(Integer):
def from_json(self, value):
try:
return int(value)
- except:
+ except Exception:
return None
diff --git a/common/lib/xmodule/xmodule/foldit_module.py b/common/lib/xmodule/xmodule/foldit_module.py
index 62c5ea416e..5ab1b327c6 100644
--- a/common/lib/xmodule/xmodule/foldit_module.py
+++ b/common/lib/xmodule/xmodule/foldit_module.py
@@ -8,7 +8,6 @@ from xmodule.x_module import XModule
from xmodule.xml_module import XmlDescriptor
from xblock.core import Scope, Integer, String
from .fields import Date
-from xmodule.util.date_utils import time_to_datetime
log = logging.getLogger(__name__)
@@ -31,9 +30,7 @@ class FolditModule(FolditFields, XModule):
css = {'scss': [resource_string(__name__, 'css/foldit/leaderboard.scss')]}
def __init__(self, *args, **kwargs):
- XModule.__init__(self, *args, **kwargs)
"""
-
Example:
"""
-
- self.due_time = time_to_datetime(self.due)
+ XModule.__init__(self, *args, **kwargs)
+ self.due_time = self.due
def is_complete(self):
"""
@@ -102,7 +99,7 @@ class FolditModule(FolditFields, XModule):
from foldit.models import Score
leaders = [(e['username'], e['score']) for e in Score.get_tops_n(10)]
- leaders.sort(key=lambda x: -x[1])
+ leaders.sort(key=lambda x:-x[1])
return leaders
diff --git a/common/lib/xmodule/xmodule/modulestore/draft.py b/common/lib/xmodule/xmodule/modulestore/draft.py
index c16c7403a9..048aea8867 100644
--- a/common/lib/xmodule/xmodule/modulestore/draft.py
+++ b/common/lib/xmodule/xmodule/modulestore/draft.py
@@ -4,6 +4,7 @@ from . import ModuleStoreBase, Location, namedtuple_to_son
from .exceptions import ItemNotFoundError
from .inheritance import own_metadata
from xmodule.exceptions import InvalidVersionError
+from pytz import UTC
DRAFT = 'draft'
# Things w/ these categories should never be marked as version='draft'
@@ -197,7 +198,7 @@ class DraftModuleStore(ModuleStoreBase):
"""
draft = self.get_item(location)
- draft.cms.published_date = datetime.utcnow()
+ draft.cms.published_date = datetime.now(UTC)
draft.cms.published_by = published_by_id
super(DraftModuleStore, self).update_item(location, draft._model_data._kvs._data)
super(DraftModuleStore, self).update_children(location, draft._model_data._kvs._children)
diff --git a/common/lib/xmodule/xmodule/modulestore/xml.py b/common/lib/xmodule/xmodule/modulestore/xml.py
index 4ea83d7e11..6ab6843216 100644
--- a/common/lib/xmodule/xmodule/modulestore/xml.py
+++ b/common/lib/xmodule/xmodule/modulestore/xml.py
@@ -52,7 +52,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
xmlstore: the XMLModuleStore to store the loaded modules in
"""
- self.unnamed = defaultdict(int) # category -> num of new url_names for that category
+ self.unnamed = defaultdict(int) # category -> num of new url_names for that category
self.used_names = defaultdict(set) # category -> set of used url_names
self.org, self.course, self.url_name = course_id.split('/')
# cdodge: adding the course_id as passed in for later reference rather than having to recomine the org/course/url_name
@@ -124,7 +124,7 @@ class ImportSystem(XMLParsingSystem, MakoDescriptorSystem):
else:
# TODO (vshnayder): We may want to enable this once course repos are cleaned up.
# (or we may want to give up on the requirement for non-state-relevant issues...)
- #error_tracker("WARNING: no name specified for module. xml='{0}...'".format(xml[:100]))
+ # error_tracker("WARNING: no name specified for module. xml='{0}...'".format(xml[:100]))
pass
# Make sure everything is unique
@@ -447,7 +447,7 @@ class XMLModuleStore(ModuleStoreBase):
def load_extra_content(self, system, course_descriptor, category, base_dir, course_dir, url_name):
self._load_extra_content(system, course_descriptor, category, base_dir, course_dir)
- # then look in a override folder based on the course run
+ # then look in a override folder based on the course run
if os.path.isdir(base_dir / url_name):
self._load_extra_content(system, course_descriptor, category, base_dir / url_name, course_dir)
diff --git a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py
index 7dc8d99451..b5d4e1b676 100644
--- a/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py
+++ b/common/lib/xmodule/xmodule/open_ended_grading_classes/openendedchild.py
@@ -16,6 +16,7 @@ from .peer_grading_service import PeerGradingService, MockPeerGradingService
import controller_query_service
from datetime import datetime
+from django.utils.timezone import UTC
log = logging.getLogger("mitx.courseware")
@@ -56,7 +57,7 @@ class OpenEndedChild(object):
POST_ASSESSMENT = 'post_assessment'
DONE = 'done'
- #This is used to tell students where they are at in the module
+ # This is used to tell students where they are at in the module
HUMAN_NAMES = {
'initial': 'Not started',
'assessing': 'In progress',
@@ -102,7 +103,7 @@ class OpenEndedChild(object):
if system.open_ended_grading_interface:
self.peer_gs = PeerGradingService(system.open_ended_grading_interface, system)
self.controller_qs = controller_query_service.ControllerQueryService(
- system.open_ended_grading_interface,system
+ system.open_ended_grading_interface, system
)
else:
self.peer_gs = MockPeerGradingService()
@@ -130,7 +131,7 @@ class OpenEndedChild(object):
pass
def closed(self):
- if self.close_date is not None and datetime.utcnow() > self.close_date:
+ if self.close_date is not None and datetime.now(UTC()) > self.close_date:
return True
return False
@@ -138,13 +139,13 @@ class OpenEndedChild(object):
if self.closed():
return True, {
'success': False,
- #This is a student_facing_error
+ # This is a student_facing_error
'error': 'The problem close date has passed, and this problem is now closed.'
}
elif self.child_attempts > self.max_attempts:
return True, {
'success': False,
- #This is a student_facing_error
+ # This is a student_facing_error
'error': 'You have attempted this problem {0} times. You are allowed {1} attempts.'.format(
self.child_attempts, self.max_attempts
)
@@ -272,7 +273,7 @@ class OpenEndedChild(object):
try:
return Progress(int(self.get_score()['score']), int(self._max_score))
except Exception as err:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Got bad progress from open ended child module. Max Score: {0}".format(self._max_score))
return None
return None
@@ -281,10 +282,10 @@ class OpenEndedChild(object):
"""
return dict out-of-sync error message, and also log.
"""
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.warning("Open ended child state out sync. state: %r, get: %r. %s",
self.child_state, get, msg)
- #This is a student_facing_error
+ # This is a student_facing_error
return {'success': False,
'error': 'The problem state got out-of-sync. Please try reloading the page.'}
@@ -391,7 +392,7 @@ class OpenEndedChild(object):
"""
overall_success = False
if not self.accept_file_upload:
- #If the question does not accept file uploads, do not do anything
+ # If the question does not accept file uploads, do not do anything
return True, get_data
has_file_to_upload, uploaded_to_s3, image_ok, image_tag = self.check_for_image_and_upload(get_data)
@@ -399,19 +400,19 @@ class OpenEndedChild(object):
get_data['student_answer'] += image_tag
overall_success = True
elif has_file_to_upload and not uploaded_to_s3 and image_ok:
- #In this case, an image was submitted by the student, but the image could not be uploaded to S3. Likely
- #a config issue (development vs deployment). For now, just treat this as a "success"
+ # In this case, an image was submitted by the student, but the image could not be uploaded to S3. Likely
+ # a config issue (development vs deployment). For now, just treat this as a "success"
log.exception("Student AJAX post to combined open ended xmodule indicated that it contained an image, "
"but the image was not able to be uploaded to S3. This could indicate a config"
"issue with this deployment, but it could also indicate a problem with S3 or with the"
"student image itself.")
overall_success = True
elif not has_file_to_upload:
- #If there is no file to upload, probably the student has embedded the link in the answer text
+ # If there is no file to upload, probably the student has embedded the link in the answer text
success, get_data['student_answer'] = self.check_for_url_in_text(get_data['student_answer'])
overall_success = success
- #log.debug("Has file: {0} Uploaded: {1} Image Ok: {2}".format(has_file_to_upload, uploaded_to_s3, image_ok))
+ # log.debug("Has file: {0} Uploaded: {1} Image Ok: {2}".format(has_file_to_upload, uploaded_to_s3, image_ok))
return overall_success, get_data
@@ -441,7 +442,7 @@ class OpenEndedChild(object):
success = False
allowed_to_submit = True
response = {}
- #This is a student_facing_error
+ # This is a student_facing_error
error_string = ("You need to peer grade {0} more in order to make another submission. "
"You have graded {1}, and {2} are required. You have made {3} successful peer grading submissions.")
try:
@@ -451,17 +452,17 @@ class OpenEndedChild(object):
student_sub_count = response['student_sub_count']
success = True
except:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.error("Could not contact external open ended graders for location {0} and student {1}".format(
self.location_string, student_id))
- #This is a student_facing_error
+ # This is a student_facing_error
error_message = "Could not contact the graders. Please notify course staff."
return success, allowed_to_submit, error_message
if count_graded >= count_required:
return success, allowed_to_submit, ""
else:
allowed_to_submit = False
- #This is a student_facing_error
+ # This is a student_facing_error
error_message = error_string.format(count_required - count_graded, count_graded, count_required,
student_sub_count)
return success, allowed_to_submit, error_message
diff --git a/common/lib/xmodule/xmodule/peer_grading_module.py b/common/lib/xmodule/xmodule/peer_grading_module.py
index ccc3e31f51..d0d6ef9242 100644
--- a/common/lib/xmodule/xmodule/peer_grading_module.py
+++ b/common/lib/xmodule/xmodule/peer_grading_module.py
@@ -15,6 +15,7 @@ from xmodule.fields import Date, StringyFloat, StringyInteger, StringyBoolean
from xmodule.open_ended_grading_classes.peer_grading_service import PeerGradingService, GradingServiceError, MockPeerGradingService
from open_ended_grading_classes import combined_open_ended_rubric
+from django.utils.timezone import UTC
log = logging.getLogger(__name__)
@@ -76,7 +77,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
def __init__(self, system, location, descriptor, model_data):
XModule.__init__(self, system, location, descriptor, model_data)
- #We need to set the location here so the child modules can use it
+ # We need to set the location here so the child modules can use it
system.set('location', location)
self.system = system
if (self.system.open_ended_grading_interface):
@@ -112,7 +113,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
if not self.ajax_url.endswith("/"):
self.ajax_url = self.ajax_url + "/"
- #StringyInteger could return None, so keep this check.
+ # StringyInteger could return None, so keep this check.
if not isinstance(self.max_grade, int):
raise TypeError("max_grade needs to be an integer.")
@@ -120,7 +121,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
return self._closed(self.timeinfo)
def _closed(self, timeinfo):
- if timeinfo.close_date is not None and datetime.utcnow() > timeinfo.close_date:
+ if timeinfo.close_date is not None and datetime.now(UTC()) > timeinfo.close_date:
return True
return False
@@ -166,9 +167,9 @@ class PeerGradingModule(PeerGradingFields, XModule):
}
if dispatch not in handlers:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.error("Cannot find {0} in handlers in handle_ajax function for open_ended_module.py".format(dispatch))
- #This is a dev_facing_error
+ # This is a dev_facing_error
return json.dumps({'error': 'Error handling action. Please try again.', 'success': False})
d = handlers[dispatch](get)
@@ -187,7 +188,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
count_required = response['count_required']
success = True
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Error getting location data from controller for location {0}, student {1}"
.format(location, student_id))
@@ -220,7 +221,7 @@ class PeerGradingModule(PeerGradingFields, XModule):
count_graded = response['count_graded']
count_required = response['count_required']
if count_required > 0 and count_graded >= count_required:
- #Ensures that once a student receives a final score for peer grading, that it does not change.
+ # Ensures that once a student receives a final score for peer grading, that it does not change.
self.student_data_for_location = response
if self.weight is not None:
@@ -271,10 +272,10 @@ class PeerGradingModule(PeerGradingFields, XModule):
response = self.peer_gs.get_next_submission(location, grader_id)
return response
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Error getting next submission. server url: {0} location: {1}, grader_id: {2}"
.format(self.peer_gs.url, location, grader_id))
- #This is a student_facing_error
+ # This is a student_facing_error
return {'success': False,
'error': EXTERNAL_GRADER_NO_CONTACT_ERROR}
@@ -314,13 +315,13 @@ class PeerGradingModule(PeerGradingFields, XModule):
score, feedback, submission_key, rubric_scores, submission_flagged)
return response
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("""Error saving grade to open ended grading service. server url: {0}, location: {1}, submission_id:{2},
submission_key: {3}, score: {4}"""
.format(self.peer_gs.url,
location, submission_id, submission_key, score)
)
- #This is a student_facing_error
+ # This is a student_facing_error
return {
'success': False,
'error': EXTERNAL_GRADER_NO_CONTACT_ERROR
@@ -356,10 +357,10 @@ class PeerGradingModule(PeerGradingFields, XModule):
response = self.peer_gs.is_student_calibrated(location, grader_id)
return response
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Error from open ended grading service. server url: {0}, grader_id: {0}, location: {1}"
.format(self.peer_gs.url, grader_id, location))
- #This is a student_facing_error
+ # This is a student_facing_error
return {
'success': False,
'error': EXTERNAL_GRADER_NO_CONTACT_ERROR
@@ -401,17 +402,17 @@ class PeerGradingModule(PeerGradingFields, XModule):
response = self.peer_gs.show_calibration_essay(location, grader_id)
return response
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Error from open ended grading service. server url: {0}, location: {0}"
.format(self.peer_gs.url, location))
- #This is a student_facing_error
+ # This is a student_facing_error
return {'success': False,
'error': EXTERNAL_GRADER_NO_CONTACT_ERROR}
# if we can't parse the rubric into HTML,
except etree.XMLSyntaxError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception("Cannot parse rubric string.")
- #This is a student_facing_error
+ # This is a student_facing_error
return {'success': False,
'error': 'Error displaying submission. Please notify course staff.'}
@@ -455,11 +456,11 @@ class PeerGradingModule(PeerGradingFields, XModule):
response['actual_rubric'] = rubric_renderer.render_rubric(response['actual_rubric'])['html']
return response
except GradingServiceError:
- #This is a dev_facing_error
+ # This is a dev_facing_error
log.exception(
"Error saving calibration grade, location: {0}, submission_key: {1}, grader_id: {2}".format(
location, submission_key, grader_id))
- #This is a student_facing_error
+ # This is a student_facing_error
return self._err_response('There was an error saving your score. Please notify course staff.')
def peer_grading_closed(self):
@@ -491,13 +492,13 @@ class PeerGradingModule(PeerGradingFields, XModule):
problem_list = problem_list_dict['problem_list']
except GradingServiceError:
- #This is a student_facing_error
+ # This is a student_facing_error
error_text = EXTERNAL_GRADER_NO_CONTACT_ERROR
log.error(error_text)
success = False
# catch error if if the json loads fails
except ValueError:
- #This is a student_facing_error
+ # This is a student_facing_error
error_text = "Could not get list of problems to peer grade. Please notify course staff."
log.error(error_text)
success = False
@@ -557,8 +558,8 @@ class PeerGradingModule(PeerGradingFields, XModule):
'''
if get is None or get.get('location') is None:
if self.use_for_single_location not in TRUE_DICT:
- #This is an error case, because it must be set to use a single location to be called without get parameters
- #This is a dev_facing_error
+ # This is an error case, because it must be set to use a single location to be called without get parameters
+ # This is a dev_facing_error
log.error(
"Peer grading problem in peer_grading_module called with no get parameters, but use_for_single_location is False.")
return {'html': "", 'success': False}
diff --git a/common/lib/xmodule/xmodule/tests/test_course_module.py b/common/lib/xmodule/xmodule/tests/test_course_module.py
index 0d789964e9..53181b5a28 100644
--- a/common/lib/xmodule/xmodule/tests/test_course_module.py
+++ b/common/lib/xmodule/xmodule/tests/test_course_module.py
@@ -1,5 +1,4 @@
import unittest
-from time import strptime
import datetime
from fs.memoryfs import MemoryFS
@@ -8,13 +7,13 @@ from mock import Mock, patch
from xmodule.modulestore.xml import ImportSystem, XMLModuleStore
import xmodule.course_module
-from xmodule.util.date_utils import time_to_datetime
+from django.utils.timezone import UTC
ORG = 'test_org'
COURSE = 'test_course'
-NOW = strptime('2013-01-01T01:00:00', '%Y-%m-%dT%H:%M:00')
+NOW = datetime.datetime.strptime('2013-01-01T01:00:00', '%Y-%m-%dT%H:%M:00').replace(tzinfo=UTC())
class DummySystem(ImportSystem):
@@ -81,10 +80,10 @@ class IsNewCourseTestCase(unittest.TestCase):
Mock(wraps=datetime.datetime)
)
mocked_datetime = datetime_patcher.start()
- mocked_datetime.utcnow.return_value = time_to_datetime(NOW)
+ mocked_datetime.now.return_value = NOW
self.addCleanup(datetime_patcher.stop)
- @patch('xmodule.course_module.time.gmtime')
+ @patch('xmodule.course_module.datetime.now')
def test_sorting_score(self, gmtime_mock):
gmtime_mock.return_value = NOW
@@ -125,7 +124,7 @@ class IsNewCourseTestCase(unittest.TestCase):
print "Comparing %s to %s" % (a, b)
assertion(a_score, b_score)
- @patch('xmodule.course_module.time.gmtime')
+ @patch('xmodule.course_module.datetime.now')
def test_start_date_text(self, gmtime_mock):
gmtime_mock.return_value = NOW
diff --git a/common/lib/xmodule/xmodule/tests/test_date_utils.py b/common/lib/xmodule/xmodule/tests/test_date_utils.py
deleted file mode 100644
index af96de018f..0000000000
--- a/common/lib/xmodule/xmodule/tests/test_date_utils.py
+++ /dev/null
@@ -1,35 +0,0 @@
-# Tests for xmodule.util.date_utils
-
-from nose.tools import assert_equals
-from xmodule.util import date_utils
-import datetime
-import time
-
-
-def test_get_time_struct_display():
- assert_equals("", date_utils.get_time_struct_display(None, ""))
- test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
- assert_equals("03/12/1992", date_utils.get_time_struct_display(test_time, '%m/%d/%Y'))
- assert_equals("15:03", date_utils.get_time_struct_display(test_time, '%H:%M'))
-
-
-def test_get_default_time_display():
- assert_equals("", date_utils.get_default_time_display(None))
- test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
- assert_equals(
- "Mar 12, 1992 at 15:03 UTC",
- date_utils.get_default_time_display(test_time))
- assert_equals(
- "Mar 12, 1992 at 15:03 UTC",
- date_utils.get_default_time_display(test_time, True))
- assert_equals(
- "Mar 12, 1992 at 15:03",
- date_utils.get_default_time_display(test_time, False))
-
-
-def test_time_to_datetime():
- assert_equals(None, date_utils.time_to_datetime(None))
- test_time = time.struct_time((1992, 3, 12, 15, 3, 30, 1, 71, 0))
- assert_equals(
- datetime.datetime(1992, 3, 12, 15, 3, 30),
- date_utils.time_to_datetime(test_time))
diff --git a/common/lib/xmodule/xmodule/tests/test_fields.py b/common/lib/xmodule/xmodule/tests/test_fields.py
index 9642f7c595..1b6c86c000 100644
--- a/common/lib/xmodule/xmodule/tests/test_fields.py
+++ b/common/lib/xmodule/xmodule/tests/test_fields.py
@@ -1,24 +1,15 @@
"""Tests for classes defined in fields.py."""
import datetime
import unittest
-from django.utils.timezone import UTC
from xmodule.fields import Date, StringyFloat, StringyInteger, StringyBoolean
-import time
+from django.utils.timezone import UTC
class DateTest(unittest.TestCase):
date = Date()
- @staticmethod
- def struct_to_datetime(struct_time):
- return datetime.datetime(struct_time.tm_year, struct_time.tm_mon,
- struct_time.tm_mday, struct_time.tm_hour,
- struct_time.tm_min, struct_time.tm_sec, tzinfo=UTC())
-
- def compare_dates(self, date1, date2, expected_delta):
- dt1 = DateTest.struct_to_datetime(date1)
- dt2 = DateTest.struct_to_datetime(date2)
- self.assertEqual(dt1 - dt2, expected_delta, str(date1) + "-"
- + str(date2) + "!=" + str(expected_delta))
+ def compare_dates(self, dt1, dt2, expected_delta):
+ self.assertEqual(dt1 - dt2, expected_delta, str(dt1) + "-"
+ + str(dt2) + "!=" + str(expected_delta))
def test_from_json(self):
'''Test conversion from iso compatible date strings to struct_time'''
@@ -55,10 +46,10 @@ class DateTest(unittest.TestCase):
def test_old_due_date_format(self):
current = datetime.datetime.today()
self.assertEqual(
- time.struct_time((current.year, 3, 12, 12, 0, 0, 1, 71, 0)),
+ datetime.datetime(current.year, 3, 12, 12, tzinfo=UTC()),
DateTest.date.from_json("March 12 12:00"))
self.assertEqual(
- time.struct_time((current.year, 12, 4, 16, 30, 0, 2, 338, 0)),
+ datetime.datetime(current.year, 12, 4, 16, 30, tzinfo=UTC()),
DateTest.date.from_json("December 4 16:30"))
def test_to_json(self):
@@ -67,7 +58,7 @@ class DateTest(unittest.TestCase):
'''
self.assertEqual(
DateTest.date.to_json(
- time.strptime("2012-12-31T23:59:59Z", "%Y-%m-%dT%H:%M:%SZ")),
+ datetime.datetime.strptime("2012-12-31T23:59:59Z", "%Y-%m-%dT%H:%M:%SZ")),
"2012-12-31T23:59:59Z")
self.assertEqual(
DateTest.date.to_json(
@@ -76,7 +67,7 @@ class DateTest(unittest.TestCase):
self.assertEqual(
DateTest.date.to_json(
DateTest.date.from_json("2012-12-31T23:00:01-01:00")),
- "2013-01-01T00:00:01Z")
+ "2012-12-31T23:00:01-01:00")
class StringyIntegerTest(unittest.TestCase):
diff --git a/common/lib/xmodule/xmodule/tests/test_import.py b/common/lib/xmodule/xmodule/tests/test_import.py
index bb0d200bb6..677dd4d80e 100644
--- a/common/lib/xmodule/xmodule/tests/test_import.py
+++ b/common/lib/xmodule/xmodule/tests/test_import.py
@@ -13,6 +13,8 @@ from xmodule.modulestore.inheritance import compute_inherited_metadata
from xmodule.fields import Date
from .test_export import DATA_DIR
+import datetime
+from django.utils.timezone import UTC
ORG = 'test_org'
COURSE = 'test_course'
@@ -40,7 +42,7 @@ class DummySystem(ImportSystem):
load_error_modules=load_error_modules,
)
- def render_template(self, template, context):
+ def render_template(self, _template, _context):
raise Exception("Shouldn't be called")
@@ -62,6 +64,7 @@ class BaseCourseTestCase(unittest.TestCase):
class ImportTestCase(BaseCourseTestCase):
+ date = Date()
def test_fallback(self):
'''Check that malformed xml loads as an ErrorDescriptor.'''
@@ -145,15 +148,18 @@ class ImportTestCase(BaseCourseTestCase):
descriptor = system.process_xml(start_xml)
compute_inherited_metadata(descriptor)
+ # pylint: disable=W0212
print(descriptor, descriptor._model_data)
- self.assertEqual(descriptor.lms.due, Date().from_json(v))
+ self.assertEqual(descriptor.lms.due, ImportTestCase.date.from_json(v))
# Check that the child inherits due correctly
child = descriptor.get_children()[0]
- self.assertEqual(child.lms.due, Date().from_json(v))
+ self.assertEqual(child.lms.due, ImportTestCase.date.from_json(v))
self.assertEqual(child._inheritable_metadata, child._inherited_metadata)
self.assertEqual(2, len(child._inherited_metadata))
- self.assertEqual('1970-01-01T00:00:00Z', child._inherited_metadata['start'])
+ self.assertLessEqual(ImportTestCase.date.from_json(
+ child._inherited_metadata['start']),
+ datetime.datetime.now(UTC()))
self.assertEqual(v, child._inherited_metadata['due'])
# Now export and check things
@@ -209,9 +215,13 @@ class ImportTestCase(BaseCourseTestCase):
# Check that the child does not inherit a value for due
child = descriptor.get_children()[0]
self.assertEqual(child.lms.due, None)
+ # pylint: disable=W0212
self.assertEqual(child._inheritable_metadata, child._inherited_metadata)
self.assertEqual(1, len(child._inherited_metadata))
- self.assertEqual('1970-01-01T00:00:00Z', child._inherited_metadata['start'])
+ # why do these tests look in the internal structure v just calling child.start?
+ self.assertLessEqual(
+ ImportTestCase.date.from_json(child._inherited_metadata['start']),
+ datetime.datetime.now(UTC()))
def test_metadata_override_default(self):
"""
@@ -230,14 +240,17 @@ class ImportTestCase(BaseCourseTestCase):
'''.format(due=course_due, org=ORG, course=COURSE, url_name=url_name)
descriptor = system.process_xml(start_xml)
child = descriptor.get_children()[0]
+ # pylint: disable=W0212
child._model_data['due'] = child_due
compute_inherited_metadata(descriptor)
- self.assertEqual(descriptor.lms.due, Date().from_json(course_due))
- self.assertEqual(child.lms.due, Date().from_json(child_due))
+ self.assertEqual(descriptor.lms.due, ImportTestCase.date.from_json(course_due))
+ self.assertEqual(child.lms.due, ImportTestCase.date.from_json(child_due))
# Test inherited metadata. Due does not appear here (because explicitly set on child).
self.assertEqual(1, len(child._inherited_metadata))
- self.assertEqual('1970-01-01T00:00:00Z', child._inherited_metadata['start'])
+ self.assertLessEqual(
+ ImportTestCase.date.from_json(child._inherited_metadata['start']),
+ datetime.datetime.now(UTC()))
# Test inheritable metadata. This has the course inheritable value for due.
self.assertEqual(2, len(child._inheritable_metadata))
self.assertEqual(course_due, child._inheritable_metadata['due'])
diff --git a/common/lib/xmodule/xmodule/timeinfo.py b/common/lib/xmodule/xmodule/timeinfo.py
index a7743b6bee..9a63c0477d 100644
--- a/common/lib/xmodule/xmodule/timeinfo.py
+++ b/common/lib/xmodule/xmodule/timeinfo.py
@@ -1,5 +1,4 @@
from .timeparse import parse_timedelta
-from xmodule.util.date_utils import time_to_datetime
import logging
log = logging.getLogger(__name__)
@@ -17,7 +16,7 @@ class TimeInfo(object):
"""
def __init__(self, due_date, grace_period_string):
if due_date is not None:
- self.display_due_date = time_to_datetime(due_date)
+ self.display_due_date = due_date
else:
self.display_due_date = None
diff --git a/common/lib/xmodule/xmodule/timeparse.py b/common/lib/xmodule/xmodule/timeparse.py
index 15a8233ccb..b189262761 100644
--- a/common/lib/xmodule/xmodule/timeparse.py
+++ b/common/lib/xmodule/xmodule/timeparse.py
@@ -1,9 +1,8 @@
"""
Helper functions for handling time in the format we like.
"""
-import time
import re
-from datetime import timedelta
+from datetime import timedelta, datetime
TIME_FORMAT = "%Y-%m-%dT%H:%M"
@@ -17,14 +16,14 @@ def parse_time(time_str):
Raises ValueError if the string is not in the right format.
"""
- return time.strptime(time_str, TIME_FORMAT)
+ return datetime.strptime(time_str, TIME_FORMAT)
-def stringify_time(time_struct):
+def stringify_time(dt):
"""
- Convert a time struct to a string
+ Convert a datetime struct to a string
"""
- return time.strftime(TIME_FORMAT, time_struct)
+ return dt.isoformat()
def parse_timedelta(time_str):
"""
diff --git a/common/lib/xmodule/xmodule/util/date_utils.py b/common/lib/xmodule/xmodule/util/date_utils.py
index 1e64856e8f..050d65fcf1 100644
--- a/common/lib/xmodule/xmodule/util/date_utils.py
+++ b/common/lib/xmodule/xmodule/util/date_utils.py
@@ -1,34 +1,20 @@
-import time
-import datetime
-
-
-def get_default_time_display(time_struct, show_timezone=True):
+def get_default_time_display(dt, show_timezone=True):
"""
- Converts a time struct to a string representation. This is the default
+ Converts a datetime to a string representation. This is the default
representation used in Studio and LMS.
It is of the form "Apr 09, 2013 at 16:00" or "Apr 09, 2013 at 16:00 UTC",
depending on the value of show_timezone.
- If None is passed in for time_struct, an empty string will be returned.
+ If None is passed in for dt, an empty string will be returned.
The default value of show_timezone is True.
"""
- timezone = "" if time_struct is None or not show_timezone else " UTC"
- return get_time_struct_display(time_struct, "%b %d, %Y at %H:%M") + timezone
-
-
-def get_time_struct_display(time_struct, format):
- """
- Converts a time struct to a string based on the given format.
-
- If None is passed in, an empty string will be returned.
- """
- return '' if time_struct is None else time.strftime(format, time_struct)
-
-
-def time_to_datetime(time_struct):
- """
- Convert a time struct to a datetime.
-
- If None is passed in, None will be returned.
- """
- return datetime.datetime(*time_struct[:6]) if time_struct else None
+ timezone = ""
+ if dt is not None and show_timezone:
+ if dt.tzinfo is not None:
+ try:
+ timezone = dt.tzinfo.tzname(dt)
+ except NotImplementedError:
+ timezone = " UTC"
+ else:
+ timezone = " UTC"
+ return dt.strftime("%b %d, %Y at %H:%M") + timezone
diff --git a/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml b/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
index 47b19f75ed..35e4704d7c 100644
--- a/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
+++ b/common/test/data/full/sequential/Administrivia_and_Circuit_Elements.xml
@@ -1,24 +1,34 @@
-
-
-
-
-
- S1E4 has been removed…
-
-
-
-
- Minor correction: Six elements (five resistors)…
-
-
+
+
+
+
+
+ S1E4 has been removed…
+
+
+
+
+ Minor correction: Six elements (five resistors)…
+
+
+
-
-
-
-
- Inline content…
-
-
-
+
+
+
+
+ Inline content…
+
+
+
diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py
index ace9c0096b..07987a8edf 100644
--- a/lms/djangoapps/courseware/access.py
+++ b/lms/djangoapps/courseware/access.py
@@ -16,6 +16,7 @@ from xmodule.x_module import XModule, XModuleDescriptor
from student.models import CourseEnrollmentAllowed
from courseware.masquerade import is_masquerading_as_student
+from django.utils.timezone import UTC
DEBUG_ACCESS = False
@@ -133,7 +134,7 @@ def _has_access_course_desc(user, course, action):
(staff can always enroll)
"""
- now = time.gmtime()
+ now = datetime.now(UTC())
start = course.enrollment_start
end = course.enrollment_end
@@ -242,7 +243,7 @@ def _has_access_descriptor(user, descriptor, action, course_context=None):
# Check start date
if descriptor.lms.start is not None:
- now = time.gmtime()
+ now = datetime.now(UTC())
effective_start = _adjust_start_date_for_beta_testers(user, descriptor)
if now > effective_start:
# after start date, everyone can see it
@@ -365,7 +366,7 @@ def _course_org_staff_group_name(location, course_context=None):
def group_names_for(role, location, course_context=None):
- """Returns the group names for a given role with this location. Plural
+ """Returns the group names for a given role with this location. Plural
because it will return both the name we expect now as well as the legacy
group name we support for backwards compatibility. This should not check
the DB for existence of a group (like some of its callers do) because that's
@@ -483,8 +484,7 @@ def _adjust_start_date_for_beta_testers(user, descriptor):
non-None start date.
Returns:
- A time, in the same format as returned by time.gmtime(). Either the same as
- start, or earlier for beta testers.
+ A datetime. Either the same as start, or earlier for beta testers.
NOTE: number of days to adjust should be cached to avoid looking it up thousands of
times per query.
@@ -505,15 +505,11 @@ def _adjust_start_date_for_beta_testers(user, descriptor):
beta_group = course_beta_test_group_name(descriptor.location)
if beta_group in user_groups:
debug("Adjust start time: user in group %s", beta_group)
- # time_structs don't support subtraction, so convert to datetimes,
- # subtract, convert back.
- # (fun fact: datetime(*a_time_struct[:6]) is the beautiful syntax for
- # converting time_structs into datetimes)
- start_as_datetime = datetime(*descriptor.lms.start[:6])
+ start_as_datetime = descriptor.lms.start
delta = timedelta(descriptor.lms.days_early_for_beta)
effective = start_as_datetime - delta
# ...and back to time_struct
- return effective.timetuple()
+ return effective
return descriptor.lms.start
@@ -564,7 +560,7 @@ def _has_access_to_location(user, location, access_level, course_context):
return True
debug("Deny: user not in groups %s", staff_groups)
- if access_level == 'instructor' or access_level == 'staff': # instructors get staff privileges
+ if access_level == 'instructor' or access_level == 'staff': # instructors get staff privileges
instructor_groups = group_names_for_instructor(location, course_context) + \
[_course_org_instructor_group_name(location, course_context)]
for instructor_group in instructor_groups:
diff --git a/lms/djangoapps/courseware/tests/test_access.py b/lms/djangoapps/courseware/tests/test_access.py
index c1bb9f203e..34d064971f 100644
--- a/lms/djangoapps/courseware/tests/test_access.py
+++ b/lms/djangoapps/courseware/tests/test_access.py
@@ -1,18 +1,12 @@
-import unittest
-import logging
-import time
-from mock import Mock, MagicMock, patch
+from mock import Mock, patch
-from django.conf import settings
from django.test import TestCase
-from xmodule.course_module import CourseDescriptor
-from xmodule.error_module import ErrorDescriptor
from xmodule.modulestore import Location
-from xmodule.timeparse import parse_time
-from xmodule.x_module import XModule, XModuleDescriptor
import courseware.access as access
from .factories import CourseEnrollmentAllowedFactory
+import datetime
+from django.utils.timezone import UTC
class AccessTestCase(TestCase):
@@ -77,7 +71,7 @@ class AccessTestCase(TestCase):
# TODO: override DISABLE_START_DATES and test the start date branch of the method
u = Mock()
d = Mock()
- d.start = time.gmtime(time.time() - 86400) # make sure the start time is in the past
+ d.start = datetime.datetime.now(UTC()) - datetime.timedelta(days=1) # make sure the start time is in the past
# Always returns true because DISABLE_START_DATES is set in test.py
self.assertTrue(access._has_access_descriptor(u, d, 'load'))
@@ -85,8 +79,8 @@ class AccessTestCase(TestCase):
def test__has_access_course_desc_can_enroll(self):
u = Mock()
- yesterday = time.gmtime(time.time() - 86400)
- tomorrow = time.gmtime(time.time() + 86400)
+ yesterday = datetime.datetime.now(UTC()) - datetime.timedelta(days=1)
+ tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1)
c = Mock(enrollment_start=yesterday, enrollment_end=tomorrow)
# User can enroll if it is between the start and end dates
diff --git a/lms/djangoapps/courseware/tests/tests.py b/lms/djangoapps/courseware/tests/tests.py
index ec3e55b1b8..f037fc6c3e 100644
--- a/lms/djangoapps/courseware/tests/tests.py
+++ b/lms/djangoapps/courseware/tests/tests.py
@@ -3,7 +3,6 @@ Test for lms courseware app
'''
import logging
import json
-import time
import random
from urlparse import urlsplit, urlunsplit
@@ -30,6 +29,8 @@ from xmodule.modulestore.django import modulestore
from xmodule.modulestore import Location
from xmodule.modulestore.xml_importer import import_from_xml
from xmodule.modulestore.xml import XMLModuleStore
+import datetime
+from django.utils.timezone import UTC
log = logging.getLogger("mitx." + __name__)
@@ -603,9 +604,9 @@ class TestViewAuth(LoginEnrollmentTestCase):
"""Actually do the test, relying on settings to be right."""
# Make courses start in the future
- tomorrow = time.time() + 24 * 3600
- self.toy.lms.start = time.gmtime(tomorrow)
- self.full.lms.start = time.gmtime(tomorrow)
+ tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1)
+ self.toy.lms.start = tomorrow
+ self.full.lms.start = tomorrow
self.assertFalse(self.toy.has_started())
self.assertFalse(self.full.has_started())
@@ -728,18 +729,18 @@ class TestViewAuth(LoginEnrollmentTestCase):
"""Actually do the test, relying on settings to be right."""
# Make courses start in the future
- tomorrow = time.time() + 24 * 3600
- nextday = tomorrow + 24 * 3600
- yesterday = time.time() - 24 * 3600
+ tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1)
+ nextday = tomorrow + datetime.timedelta(days=1)
+ yesterday = datetime.datetime.now(UTC()) - datetime.timedelta(days=1)
print "changing"
# toy course's enrollment period hasn't started
- self.toy.enrollment_start = time.gmtime(tomorrow)
- self.toy.enrollment_end = time.gmtime(nextday)
+ self.toy.enrollment_start = tomorrow
+ self.toy.enrollment_end = nextday
# full course's has
- self.full.enrollment_start = time.gmtime(yesterday)
- self.full.enrollment_end = time.gmtime(tomorrow)
+ self.full.enrollment_start = yesterday
+ self.full.enrollment_end = tomorrow
print "login"
# First, try with an enrolled student
@@ -778,12 +779,10 @@ class TestViewAuth(LoginEnrollmentTestCase):
self.assertFalse(settings.MITX_FEATURES['DISABLE_START_DATES'])
# Make courses start in the future
- tomorrow = time.time() + 24 * 3600
- # nextday = tomorrow + 24 * 3600
- # yesterday = time.time() - 24 * 3600
+ tomorrow = datetime.datetime.now(UTC()) + datetime.timedelta(days=1)
# toy course's hasn't started
- self.toy.lms.start = time.gmtime(tomorrow)
+ self.toy.lms.start = tomorrow
self.assertFalse(self.toy.has_started())
# but should be accessible for beta testers
@@ -854,7 +853,7 @@ class TestSubmittingProblems(LoginEnrollmentTestCase):
modx_url = self.modx_url(problem_location, 'problem_check')
answer_key_prefix = 'input_i4x-edX-{}-problem-{}_'.format(self.course_slug, problem_url_name)
resp = self.client.post(modx_url,
- { (answer_key_prefix + k): v for k,v in responses.items() }
+ { (answer_key_prefix + k): v for k, v in responses.items() }
)
return resp
@@ -925,7 +924,7 @@ class TestCourseGrader(TestSubmittingProblems):
# Only get half of the first problem correct
self.submit_question_answer('H1P1', {'2_1': 'Correct', '2_2': 'Incorrect'})
self.check_grade_percent(0.06)
- self.assertEqual(earned_hw_scores(), [1.0, 0, 0]) # Order matters
+ self.assertEqual(earned_hw_scores(), [1.0, 0, 0]) # Order matters
self.assertEqual(score_for_hw('Homework1'), [1.0, 0.0])
# Get both parts of the first problem correct
@@ -958,16 +957,16 @@ class TestCourseGrader(TestSubmittingProblems):
# Third homework
self.submit_question_answer('H3P1', {'2_1': 'Correct', '2_2': 'Correct'})
- self.check_grade_percent(0.42) # Score didn't change
+ self.check_grade_percent(0.42) # Score didn't change
self.assertEqual(earned_hw_scores(), [4.0, 4.0, 2.0])
self.submit_question_answer('H3P2', {'2_1': 'Correct', '2_2': 'Correct'})
- self.check_grade_percent(0.5) # Now homework2 dropped. Score changes
+ self.check_grade_percent(0.5) # Now homework2 dropped. Score changes
self.assertEqual(earned_hw_scores(), [4.0, 4.0, 4.0])
# Now we answer the final question (worth half of the grade)
self.submit_question_answer('FinalQuestion', {'2_1': 'Correct', '2_2': 'Correct'})
- self.check_grade_percent(1.0) # Hooray! We got 100%
+ self.check_grade_percent(1.0) # Hooray! We got 100%
@override_settings(MODULESTORE=TEST_DATA_XML_MODULESTORE)
@@ -1000,7 +999,7 @@ class TestSchematicResponse(TestSubmittingProblems):
{ '2_1': json.dumps(
[['transient', {'Z': [
[0.0000004, 2.8],
- [0.0000009, 0.0], # wrong.
+ [0.0000009, 0.0], # wrong.
[0.0000014, 2.8],
[0.0000019, 2.8],
[0.0000024, 2.8],
diff --git a/lms/djangoapps/django_comment_client/utils.py b/lms/djangoapps/django_comment_client/utils.py
index 276956f0e9..007a8fedfd 100644
--- a/lms/djangoapps/django_comment_client/utils.py
+++ b/lms/djangoapps/django_comment_client/utils.py
@@ -1,14 +1,9 @@
-import time
from collections import defaultdict
import logging
-import time
import urllib
from datetime import datetime
from courseware.module_render import get_module
-from xmodule.modulestore import Location
-from xmodule.modulestore.django import modulestore
-from xmodule.modulestore.search import path_to_location
from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from django.db import connection
@@ -16,13 +11,12 @@ from django.http import HttpResponse
from django.utils import simplejson
from django_comment_common.models import Role
from django_comment_client.permissions import check_permissions_by_view
-from xmodule.modulestore.exceptions import NoPathToItem
from mitxmako import middleware
import pystache_custom as pystache
-from xmodule.modulestore import Location
from xmodule.modulestore.django import modulestore
+from django.utils.timezone import UTC
log = logging.getLogger(__name__)
@@ -100,7 +94,7 @@ def get_discussion_category_map(course):
def filter_unstarted_categories(category_map):
- now = time.gmtime()
+ now = datetime.now(UTC())
result_map = {}
@@ -220,7 +214,7 @@ def initialize_discussion_info(course):
for topic, entry in course.discussion_topics.items():
category_map['entries'][topic] = {"id": entry["id"],
"sort_key": entry.get("sort_key", topic),
- "start_date": time.gmtime()}
+ "start_date": datetime.now(UTC())}
sort_map_entries(category_map)
_DISCUSSIONINFO[course.id]['id_map'] = discussion_id_map
@@ -292,7 +286,7 @@ def get_ability(course_id, content, user):
'can_vote': check_permissions_by_view(user, course_id, content, "vote_for_thread" if content['type'] == 'thread' else "vote_for_comment"),
}
-#TODO: RENAME
+# TODO: RENAME
def get_annotated_content_info(course_id, content, user, user_info):
@@ -310,7 +304,7 @@ def get_annotated_content_info(course_id, content, user, user_info):
'ability': get_ability(course_id, content, user),
}
-#TODO: RENAME
+# TODO: RENAME
def get_annotated_content_infos(course_id, thread, user, user_info):