Unicode changes to support QRF
fixing unit tests fixing merge error fixing xqueue submission issue with unicode url (trial 0.1) fixing fotmats as commented upon removing yaml file language selection Unicode changes to support QRF removed unnecessary pass in modulestore/init.py fixing merge error fixing fotmats as commented upon removing yaml file language selection fixing pep8 violations - fixing pylint violations pylint violation fixing line spaces and formats ignore pylint E1101 remove empty line fixing pylint violations pep8 violations bulk mail unicode/decode fix migration error fix pep8 just to push again more unicode/decode Final changes to comments and error messages.
This commit is contained in:
@@ -143,7 +143,7 @@ def get_lms_link_for_item(location, preview=False, course_id=None):
|
||||
else:
|
||||
lms_base = settings.LMS_BASE
|
||||
|
||||
lms_link = "//{lms_base}/courses/{course_id}/jump_to/{location}".format(
|
||||
lms_link = u"//{lms_base}/courses/{course_id}/jump_to/{location}".format(
|
||||
lms_base=lms_base,
|
||||
course_id=course_id,
|
||||
location=Location(location)
|
||||
@@ -179,7 +179,7 @@ def get_lms_link_for_about_page(location):
|
||||
about_base = None
|
||||
|
||||
if about_base is not None:
|
||||
lms_link = "//{about_base_url}/courses/{course_id}/about".format(
|
||||
lms_link = u"//{about_base_url}/courses/{course_id}/about".format(
|
||||
about_base_url=about_base,
|
||||
course_id=Location(location).course_id
|
||||
)
|
||||
|
||||
@@ -267,8 +267,7 @@ def unit_handler(request, tag=None, package_id=None, branch=None, version_guid=N
|
||||
preview_lms_base = settings.FEATURES.get('PREVIEW_LMS_BASE')
|
||||
|
||||
preview_lms_link = (
|
||||
'//{preview_lms_base}/courses/{org}/{course}/'
|
||||
'{course_name}/courseware/{section}/{subsection}/{index}'
|
||||
u'//{preview_lms_base}/courses/{org}/{course}/{course_name}/courseware/{section}/{subsection}/{index}'
|
||||
).format(
|
||||
preview_lms_base=preview_lms_base,
|
||||
lms_base=settings.LMS_BASE,
|
||||
|
||||
@@ -251,7 +251,7 @@ def create_new_course(request):
|
||||
run = request.json.get('run')
|
||||
|
||||
try:
|
||||
dest_location = Location('i4x', org, number, 'course', run)
|
||||
dest_location = Location(u'i4x', org, number, u'course', run)
|
||||
except InvalidLocationError as error:
|
||||
return JsonResponse({
|
||||
"ErrMsg": _("Unable to create course '{name}'.\n\n{err}").format(
|
||||
@@ -286,8 +286,10 @@ def create_new_course(request):
|
||||
course_search_location = bson.son.SON({
|
||||
'_id.tag': 'i4x',
|
||||
# cannot pass regex to Location constructor; thus this hack
|
||||
'_id.org': re.compile('^{}$'.format(dest_location.org), re.IGNORECASE),
|
||||
'_id.course': re.compile('^{}$'.format(dest_location.course), re.IGNORECASE),
|
||||
# pylint: disable=E1101
|
||||
'_id.org': re.compile(u'^{}$'.format(dest_location.org), re.IGNORECASE | re.UNICODE),
|
||||
# pylint: disable=E1101
|
||||
'_id.course': re.compile(u'^{}$'.format(dest_location.course), re.IGNORECASE | re.UNICODE),
|
||||
'_id.category': 'course',
|
||||
})
|
||||
courses = modulestore().collection.find(course_search_location, fields=('_id'))
|
||||
|
||||
@@ -41,7 +41,7 @@ def handler_prefix(block, handler='', suffix=''):
|
||||
Trailing `/`s are removed from the returned url.
|
||||
"""
|
||||
return reverse('preview_handler', kwargs={
|
||||
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'usage_id': quote_slashes(unicode(block.scope_ids.usage_id).encode('utf-8')),
|
||||
'handler': handler,
|
||||
'suffix': suffix,
|
||||
}).rstrip('/?')
|
||||
|
||||
@@ -84,8 +84,8 @@ require(["domReady", "jquery", "underscore", "js/utils/cancel_on_escape"],
|
||||
if (required) {
|
||||
return required;
|
||||
}
|
||||
if (item !== encodeURIComponent(item)) {
|
||||
return gettext('Please do not use any spaces or special characters in this field.');
|
||||
if (/\s/g.test(item)) {
|
||||
return gettext('Please do not use any spaces in this field.');
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
@@ -164,7 +164,7 @@ require(["domReady!", "jquery", "js/models/module_info", "coffee/src/views/unit"
|
||||
% endif
|
||||
${_("with the subsection {link_start}{name}{link_end}").format(
|
||||
name=subsection.display_name_with_default,
|
||||
link_start='<a href="{url}">'.format(url=subsection_url),
|
||||
link_start=u'<a href="{url}">'.format(url=subsection_url),
|
||||
link_end='</a>',
|
||||
)}
|
||||
</p>
|
||||
|
||||
@@ -110,12 +110,12 @@ def instance_key(model, instance_or_pk):
|
||||
|
||||
|
||||
def set_cached_content(content):
|
||||
cache.set(str(content.location), content)
|
||||
cache.set(unicode(content.location).encode("utf-8"), content)
|
||||
|
||||
|
||||
def get_cached_content(location):
|
||||
return cache.get(str(location))
|
||||
return cache.get(unicode(location).encode("utf-8"))
|
||||
|
||||
|
||||
def del_cached_content(location):
|
||||
cache.delete(str(location))
|
||||
cache.delete(unicode(location).encode("utf-8"))
|
||||
|
||||
@@ -77,7 +77,7 @@ def is_commentable_cohorted(course_id, commentable_id):
|
||||
# inline discussions are cohorted by default
|
||||
ans = True
|
||||
|
||||
log.debug("is_commentable_cohorted({0}, {1}) = {2}".format(course_id,
|
||||
log.debug(u"is_commentable_cohorted({0}, {1}) = {2}".format(course_id,
|
||||
commentable_id,
|
||||
ans))
|
||||
return ans
|
||||
|
||||
@@ -19,7 +19,7 @@ def _url_replace_regex(prefix):
|
||||
To anyone contemplating making this more complicated:
|
||||
http://xkcd.com/1171/
|
||||
"""
|
||||
return r"""
|
||||
return ur"""
|
||||
(?x) # flags=re.VERBOSE
|
||||
(?P<quote>\\?['"]) # the opening quotes
|
||||
(?P<prefix>{prefix}) # the prefix
|
||||
@@ -152,7 +152,7 @@ def replace_static_urls(text, data_directory, course_id=None, static_asset_path=
|
||||
return "".join([quote, url, quote])
|
||||
|
||||
return re.sub(
|
||||
_url_replace_regex('(?:{static_url}|/static/)(?!{data_dir})'.format(
|
||||
_url_replace_regex(u'(?:{static_url}|/static/)(?!{data_dir})'.format(
|
||||
static_url=settings.STATIC_URL,
|
||||
data_dir=static_asset_path or data_directory
|
||||
)),
|
||||
|
||||
@@ -159,30 +159,30 @@ class CourseRole(GroupBasedRole):
|
||||
|
||||
if isinstance(self.location, Location):
|
||||
try:
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.course_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.course_id))
|
||||
course_context = self.location.course_id # course_id is valid for translation
|
||||
except InvalidLocationError: # will occur on old locations where location is not of category course
|
||||
if course_context is None:
|
||||
raise CourseContextRequired()
|
||||
else:
|
||||
groupnames.append('{0}_{1}'.format(role, course_context))
|
||||
groupnames.append(u'{0}_{1}'.format(role, course_context))
|
||||
try:
|
||||
locator = loc_mapper().translate_location_to_course_locator(course_context, self.location)
|
||||
groupnames.append('{0}_{1}'.format(role, locator.package_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, locator.package_id))
|
||||
except (InvalidLocationError, ItemNotFoundError):
|
||||
# if it's never been mapped, the auth won't be via the Locator syntax
|
||||
pass
|
||||
# least preferred legacy role_course format
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.course))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.course)) # pylint: disable=E1101, E1103
|
||||
elif isinstance(self.location, CourseLocator):
|
||||
groupnames.append('{0}_{1}'.format(role, self.location.package_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, self.location.package_id))
|
||||
# handle old Location syntax
|
||||
old_location = loc_mapper().translate_locator_to_location(self.location, get_course=True)
|
||||
if old_location:
|
||||
# the slashified version of the course_id (myu/mycourse/myrun)
|
||||
groupnames.append('{0}_{1}'.format(role, old_location.course_id))
|
||||
groupnames.append(u'{0}_{1}'.format(role, old_location.course_id))
|
||||
# add the least desirable but sometimes occurring format.
|
||||
groupnames.append('{0}_{1}'.format(role, old_location.course))
|
||||
groupnames.append(u'{0}_{1}'.format(role, old_location.course)) # pylint: disable=E1101, E1103
|
||||
|
||||
super(CourseRole, self).__init__(groupnames)
|
||||
|
||||
@@ -193,12 +193,13 @@ class OrgRole(GroupBasedRole):
|
||||
"""
|
||||
def __init__(self, role, location):
|
||||
location = Location(location)
|
||||
super(OrgRole, self).__init__(['{}_{}'.format(role, location.org)])
|
||||
super(OrgRole, self).__init__([u'{}_{}'.format(role, location.org)])
|
||||
|
||||
|
||||
class CourseStaffRole(CourseRole):
|
||||
"""A Staff member of a course"""
|
||||
ROLE = 'staff'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(CourseStaffRole, self).__init__(self.ROLE, *args, **kwargs)
|
||||
|
||||
|
||||
@@ -353,7 +353,7 @@ def dashboard(request):
|
||||
|
||||
course_enrollment_pairs.append((course, enrollment))
|
||||
except ItemNotFoundError:
|
||||
log.error("User {0} enrolled in non-existent course {1}"
|
||||
log.error(u"User {0} enrolled in non-existent course {1}"
|
||||
.format(user.username, enrollment.course_id))
|
||||
|
||||
course_optouts = Optout.objects.filter(user=user).values_list('course_id', flat=True)
|
||||
@@ -495,9 +495,9 @@ def change_enrollment(request):
|
||||
org, course_num, run = course_id.split("/")
|
||||
dog_stats_api.increment(
|
||||
"common.student.enrollment",
|
||||
tags=["org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run)]
|
||||
tags=[u"org:{0}".format(org),
|
||||
u"course:{0}".format(course_num),
|
||||
u"run:{0}".format(run)]
|
||||
)
|
||||
|
||||
CourseEnrollment.enroll(user, course.id, mode=current_mode.slug)
|
||||
|
||||
@@ -372,7 +372,7 @@ class LoncapaProblem(object):
|
||||
# TODO: figure out where to get file submissions when rescoring.
|
||||
if 'filesubmission' in responder.allowed_inputfields and student_answers is None:
|
||||
_ = self.capa_system.i18n.ugettext
|
||||
raise Exception(_("Cannot rescore problems with possible file submissions"))
|
||||
raise Exception(_(u"Cannot rescore problems with possible file submissions"))
|
||||
|
||||
# use 'student_answers' only if it is provided, and if it might contain a file
|
||||
# submission that would not exist in the persisted "student_answers".
|
||||
|
||||
@@ -50,7 +50,7 @@ class CorrectMap(object):
|
||||
):
|
||||
|
||||
if answer_id is not None:
|
||||
self.cmap[str(answer_id)] = {
|
||||
self.cmap[answer_id] = {
|
||||
'correctness': correctness,
|
||||
'npoints': npoints,
|
||||
'msg': msg,
|
||||
|
||||
@@ -62,7 +62,7 @@ class XQueueInterface(object):
|
||||
"""
|
||||
|
||||
def __init__(self, url, django_auth, requests_auth=None):
|
||||
self.url = url
|
||||
self.url = unicode(url)
|
||||
self.auth = django_auth
|
||||
self.session = requests.Session()
|
||||
self.session.auth = requests_auth
|
||||
|
||||
@@ -34,7 +34,9 @@ class StaticContent(object):
|
||||
|
||||
@staticmethod
|
||||
def generate_thumbnail_name(original_name):
|
||||
return ('{0}' + XASSET_THUMBNAIL_TAIL_NAME).format(os.path.splitext(original_name)[0])
|
||||
return u"{name_root}{extension}".format(
|
||||
name_root=os.path.splitext(original_name)[0],
|
||||
extension=XASSET_THUMBNAIL_TAIL_NAME,)
|
||||
|
||||
@staticmethod
|
||||
def compute_location(org, course, name, revision=None, is_thumbnail=False):
|
||||
@@ -64,7 +66,7 @@ class StaticContent(object):
|
||||
"""
|
||||
Returns a boolean if a path is believed to be a c4x link based on the leading element
|
||||
"""
|
||||
return path_string.startswith('/{0}/'.format(XASSET_LOCATION_TAG))
|
||||
return path_string.startswith(u'/{0}/'.format(XASSET_LOCATION_TAG))
|
||||
|
||||
@staticmethod
|
||||
def renamespace_c4x_path(path_string, target_location):
|
||||
@@ -86,14 +88,14 @@ class StaticContent(object):
|
||||
the actual /c4x/... path which the client needs to reference static content
|
||||
"""
|
||||
if location is not None:
|
||||
return "/static/{name}".format(**location.dict())
|
||||
return u"/static/{name}".format(**location.dict())
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def get_base_url_path_for_course_assets(loc):
|
||||
if loc is not None:
|
||||
return "/c4x/{org}/{course}/asset".format(**loc.dict())
|
||||
return u"/c4x/{org}/{course}/asset".format(**loc.dict())
|
||||
|
||||
@staticmethod
|
||||
def get_id_from_location(location):
|
||||
@@ -237,6 +239,6 @@ class ContentStore(object):
|
||||
|
||||
except Exception, e:
|
||||
# log and continue as thumbnails are generally considered as optional
|
||||
logging.exception("Failed to generate thumbnail for {0}. Exception: {1}".format(content.location, str(e)))
|
||||
logging.exception(u"Failed to generate thumbnail for {0}. Exception: {1}".format(content.location, str(e)))
|
||||
|
||||
return thumbnail_content, thumbnail_file_location
|
||||
|
||||
@@ -30,12 +30,12 @@ URL_RE = re.compile("""
|
||||
|
||||
# TODO (cpennington): We should decide whether we want to expand the
|
||||
# list of valid characters in a location
|
||||
INVALID_CHARS = re.compile(r"[^\w.-]")
|
||||
INVALID_CHARS = re.compile(r"[^\w.%-]", re.UNICODE)
|
||||
# Names are allowed to have colons.
|
||||
INVALID_CHARS_NAME = re.compile(r"[^\w.:-]")
|
||||
INVALID_CHARS_NAME = re.compile(r"[^\w.:%-]", re.UNICODE)
|
||||
|
||||
# html ids can contain word chars and dashes
|
||||
INVALID_HTML_CHARS = re.compile(r"[^\w-]")
|
||||
INVALID_HTML_CHARS = re.compile(r"[^\w-]", re.UNICODE)
|
||||
|
||||
_LocationBase = namedtuple('LocationBase', 'tag org course category name revision')
|
||||
|
||||
@@ -186,14 +186,14 @@ class Location(_LocationBase):
|
||||
elif isinstance(location, basestring):
|
||||
match = URL_RE.match(location)
|
||||
if match is None:
|
||||
log.debug("location %r doesn't match URL", location)
|
||||
log.debug(u"location %r doesn't match URL", location)
|
||||
raise InvalidLocationError(location)
|
||||
groups = match.groupdict()
|
||||
check_dict(groups)
|
||||
return _LocationBase.__new__(_cls, **groups)
|
||||
elif isinstance(location, (list, tuple)):
|
||||
if len(location) not in (5, 6):
|
||||
log.debug('location has wrong length')
|
||||
log.debug(u'location has wrong length')
|
||||
raise InvalidLocationError(location)
|
||||
|
||||
if len(location) == 5:
|
||||
@@ -216,9 +216,9 @@ class Location(_LocationBase):
|
||||
"""
|
||||
Return a string containing the URL for this location
|
||||
"""
|
||||
url = "{0.tag}://{0.org}/{0.course}/{0.category}/{0.name}".format(self)
|
||||
url = u"{0.tag}://{0.org}/{0.course}/{0.category}/{0.name}".format(self)
|
||||
if self.revision:
|
||||
url += "@" + self.revision
|
||||
url += u"@{rev}".format(rev=self.revision) # pylint: disable=E1101
|
||||
return url
|
||||
|
||||
def html_id(self):
|
||||
@@ -226,7 +226,7 @@ class Location(_LocationBase):
|
||||
Return a string with a version of the location that is safe for use in
|
||||
html id attributes
|
||||
"""
|
||||
id_string = "-".join(str(v) for v in self.list() if v is not None)
|
||||
id_string = u"-".join(v for v in self.list() if v is not None)
|
||||
return Location.clean_for_html(id_string)
|
||||
|
||||
def dict(self):
|
||||
@@ -240,6 +240,9 @@ class Location(_LocationBase):
|
||||
return list(self)
|
||||
|
||||
def __str__(self):
|
||||
return str(self.url().encode("utf-8"))
|
||||
|
||||
def __unicode__(self):
|
||||
return self.url()
|
||||
|
||||
def __repr__(self):
|
||||
@@ -254,7 +257,7 @@ class Location(_LocationBase):
|
||||
Throws an InvalidLocationError is this location does not represent a course.
|
||||
"""
|
||||
if self.category != 'course':
|
||||
raise InvalidLocationError('Cannot call course_id for {0} because it is not of category course'.format(self))
|
||||
raise InvalidLocationError(u'Cannot call course_id for {0} because it is not of category course'.format(self))
|
||||
|
||||
return "/".join([self.org, self.course, self.name])
|
||||
|
||||
|
||||
@@ -88,9 +88,9 @@ class LocMapperStore(object):
|
||||
"""
|
||||
if package_id is None:
|
||||
if course_location.category == 'course':
|
||||
package_id = "{0.org}.{0.course}.{0.name}".format(course_location)
|
||||
package_id = u"{0.org}.{0.course}.{0.name}".format(course_location)
|
||||
else:
|
||||
package_id = "{0.org}.{0.course}".format(course_location)
|
||||
package_id = u"{0.org}.{0.course}".format(course_location)
|
||||
# very like _interpret_location_id but w/o the _id
|
||||
location_id = self._construct_location_son(
|
||||
course_location.org, course_location.course,
|
||||
@@ -185,7 +185,6 @@ class LocMapperStore(object):
|
||||
self._cache_location_map_entry(old_style_course_id, location, published_usage, draft_usage)
|
||||
return result
|
||||
|
||||
|
||||
def translate_locator_to_location(self, locator, get_course=False):
|
||||
"""
|
||||
Returns an old style Location for the given Locator if there's an appropriate entry in the
|
||||
@@ -331,12 +330,12 @@ class LocMapperStore(object):
|
||||
# strip id envelope if any
|
||||
entry_id = entry_id.get('_id', entry_id)
|
||||
if entry_id.get('name', False):
|
||||
return '{0[org]}/{0[course]}/{0[name]}'.format(entry_id)
|
||||
return u'{0[org]}/{0[course]}/{0[name]}'.format(entry_id)
|
||||
elif entry_id.get('_id.org', False):
|
||||
# the odd format one
|
||||
return '{0[_id.org]}/{0[_id.course]}'.format(entry_id)
|
||||
return u'{0[_id.org]}/{0[_id.course]}'.format(entry_id)
|
||||
else:
|
||||
return '{0[org]}/{0[course]}'.format(entry_id)
|
||||
return u'{0[org]}/{0[course]}'.format(entry_id)
|
||||
|
||||
def _construct_location_son(self, org, course, name=None):
|
||||
"""
|
||||
@@ -392,7 +391,7 @@ class LocMapperStore(object):
|
||||
"""
|
||||
See if the location x published pair is in the cache. If so, return the mapped locator.
|
||||
"""
|
||||
entry = self.cache.get('{}+{}'.format(old_course_id, location.url()))
|
||||
entry = self.cache.get(u'{}+{}'.format(old_course_id, location.url()))
|
||||
if entry is not None:
|
||||
if published:
|
||||
return entry[0]
|
||||
@@ -424,7 +423,7 @@ class LocMapperStore(object):
|
||||
See if the package_id is in the cache. If so, return the mapped location to the
|
||||
course root.
|
||||
"""
|
||||
return self.cache.get('courseId+{}'.format(locator_package_id))
|
||||
return self.cache.get(u'courseId+{}'.format(locator_package_id))
|
||||
|
||||
def _cache_course_locator(self, old_course_id, published_course_locator, draft_course_locator):
|
||||
"""
|
||||
@@ -442,9 +441,9 @@ class LocMapperStore(object):
|
||||
"""
|
||||
setmany = {}
|
||||
if location.category == 'course':
|
||||
setmany['courseId+{}'.format(published_usage.package_id)] = location
|
||||
setmany[u'courseId+{}'.format(published_usage.package_id)] = location
|
||||
setmany[unicode(published_usage)] = location
|
||||
setmany[unicode(draft_usage)] = location
|
||||
setmany['{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
|
||||
setmany[u'{}+{}'.format(old_course_id, location.url())] = (published_usage, draft_usage)
|
||||
setmany[old_course_id] = (published_usage, draft_usage)
|
||||
self.cache.set_many(setmany)
|
||||
|
||||
@@ -64,13 +64,13 @@ class Locator(object):
|
||||
'''
|
||||
str(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return unicode(self).encode('utf8')
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
def __unicode__(self):
|
||||
'''
|
||||
unicode(self) returns something like this: "mit.eecs.6002x"
|
||||
'''
|
||||
return self.url()
|
||||
return unicode(self).encode('utf-8')
|
||||
|
||||
@abstractmethod
|
||||
def version(self):
|
||||
@@ -199,12 +199,12 @@ class CourseLocator(Locator):
|
||||
Return a string representing this location.
|
||||
"""
|
||||
if self.package_id:
|
||||
result = self.package_id
|
||||
result = unicode(self.package_id)
|
||||
if self.branch:
|
||||
result += '/' + BRANCH_PREFIX + self.branch
|
||||
return result
|
||||
elif self.version_guid:
|
||||
return VERSION_PREFIX + str(self.version_guid)
|
||||
return u"{prefix}{guid}".format(prefix=VERSION_PREFIX, guid=self.version_guid)
|
||||
else:
|
||||
# raise InsufficientSpecificationError("missing package_id or version_guid")
|
||||
return '<InsufficientSpecificationError: missing package_id or version_guid>'
|
||||
@@ -213,7 +213,7 @@ class CourseLocator(Locator):
|
||||
"""
|
||||
Return a string containing the URL for this location.
|
||||
"""
|
||||
return 'edx://' + unicode(self)
|
||||
return u'edx://' + unicode(self)
|
||||
|
||||
def _validate_args(self, url, version_guid, package_id):
|
||||
"""
|
||||
@@ -526,7 +526,7 @@ class DefinitionLocator(Locator):
|
||||
Return a string containing the URL for this location.
|
||||
url(self) returns something like this: 'defx://version/519665f6223ebd6980884f2b'
|
||||
"""
|
||||
return 'defx://' + unicode(self)
|
||||
return u'defx://' + unicode(self)
|
||||
|
||||
def version(self):
|
||||
"""
|
||||
|
||||
@@ -7,7 +7,8 @@ BLOCK_PREFIX = r"block/"
|
||||
# Prefix for the version portion of a locator URL, when it is preceded by a course ID
|
||||
VERSION_PREFIX = r"version/"
|
||||
|
||||
ALLOWED_ID_CHARS = r'[a-zA-Z0-9_\-~.:]'
|
||||
ALLOWED_ID_CHARS = r'[\w\-~.:]'
|
||||
|
||||
|
||||
URL_RE_SOURCE = r"""
|
||||
(?P<tag>edx://)?
|
||||
@@ -20,7 +21,7 @@ URL_RE_SOURCE = r"""
|
||||
VERSION_PREFIX=VERSION_PREFIX, BLOCK_PREFIX=BLOCK_PREFIX
|
||||
)
|
||||
|
||||
URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE)
|
||||
URL_RE = re.compile('^' + URL_RE_SOURCE + '$', re.IGNORECASE | re.VERBOSE | re.UNICODE)
|
||||
|
||||
|
||||
def parse_url(string, tag_optional=False):
|
||||
@@ -54,7 +55,7 @@ def parse_url(string, tag_optional=False):
|
||||
return matched_dict
|
||||
|
||||
|
||||
BLOCK_RE = re.compile(r'^' + ALLOWED_ID_CHARS + r'+$', re.IGNORECASE)
|
||||
BLOCK_RE = re.compile(r'^' + ALLOWED_ID_CHARS + r'+$', re.IGNORECASE | re.UNICODE)
|
||||
|
||||
|
||||
def parse_block_ref(string):
|
||||
|
||||
@@ -73,13 +73,13 @@ def rewrite_nonportable_content_links(source_course_id, dest_course_id, text):
|
||||
# NOTE: ultimately link updating is not a hard requirement, so if something blows up with
|
||||
# the regex subsitution, log the error and continue
|
||||
try:
|
||||
c4x_link_base = '{0}/'.format(StaticContent.get_base_url_path_for_course_assets(course_location))
|
||||
c4x_link_base = u'{0}/'.format(StaticContent.get_base_url_path_for_course_assets(course_location))
|
||||
text = re.sub(_prefix_only_url_replace_regex(c4x_link_base), portable_asset_link_subtitution, text)
|
||||
except Exception, e:
|
||||
logging.warning("Error going regex subtituion %r on text = %r.\n\nError msg = %s", c4x_link_base, text, str(e))
|
||||
|
||||
try:
|
||||
jump_to_link_base = '/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/'.format(
|
||||
jump_to_link_base = u'/courses/{org}/{course}/{run}/jump_to/i4x://{org}/{course}/'.format(
|
||||
org=org, course=course, run=run
|
||||
)
|
||||
text = re.sub(_prefix_and_category_url_replace_regex(jump_to_link_base), portable_jump_to_link_substitution, text)
|
||||
@@ -94,7 +94,7 @@ def rewrite_nonportable_content_links(source_course_id, dest_course_id, text):
|
||||
#
|
||||
if source_course_id != dest_course_id:
|
||||
try:
|
||||
generic_courseware_link_base = '/courses/{org}/{course}/{run}/'.format(
|
||||
generic_courseware_link_base = u'/courses/{org}/{course}/{run}/'.format(
|
||||
org=org, course=course, run=run
|
||||
)
|
||||
text = re.sub(_prefix_only_url_replace_regex(generic_courseware_link_base), portable_asset_link_subtitution, text)
|
||||
|
||||
@@ -129,9 +129,9 @@ class ConditionalModuleBasicTest(unittest.TestCase):
|
||||
html = modules['cond_module'].render('student_view').content
|
||||
expected = modules['cond_module'].xmodule_runtime.render_template('conditional_ajax.html', {
|
||||
'ajax_url': modules['cond_module'].xmodule_runtime.ajax_url,
|
||||
'element_id': 'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'id': 'i4x://edX/conditional_test/conditional/SampleConditional',
|
||||
'depends': 'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
'element_id': u'i4x-edX-conditional_test-conditional-SampleConditional',
|
||||
'id': u'i4x://edX/conditional_test/conditional/SampleConditional',
|
||||
'depends': u'i4x-edX-conditional_test-problem-SampleProblem',
|
||||
})
|
||||
self.assertEquals(expected, html)
|
||||
|
||||
@@ -225,9 +225,9 @@ class ConditionalModuleXmlTest(unittest.TestCase):
|
||||
{
|
||||
# Test ajax url is just usage-id / handler_name
|
||||
'ajax_url': 'i4x://HarvardX/ER22x/conditional/condone/xmodule_handler',
|
||||
'element_id': 'i4x-HarvardX-ER22x-conditional-condone',
|
||||
'id': 'i4x://HarvardX/ER22x/conditional/condone',
|
||||
'depends': 'i4x-HarvardX-ER22x-problem-choiceprob'
|
||||
'element_id': u'i4x-HarvardX-ER22x-conditional-condone',
|
||||
'id': u'i4x://HarvardX/ER22x/conditional/condone',
|
||||
'depends': u'i4x-HarvardX-ER22x-problem-choiceprob'
|
||||
}
|
||||
)
|
||||
self.assertEqual(html, html_expect)
|
||||
|
||||
@@ -223,7 +223,7 @@ class XModuleMixin(XBlockMixin):
|
||||
try:
|
||||
child = self.runtime.get_block(child_loc)
|
||||
except ItemNotFoundError:
|
||||
log.exception('Unable to load item {loc}, skipping'.format(loc=child_loc))
|
||||
log.exception(u'Unable to load item {loc}, skipping'.format(loc=child_loc))
|
||||
continue
|
||||
self._child_instances.append(child)
|
||||
|
||||
@@ -538,7 +538,6 @@ class ResourceTemplates(object):
|
||||
template = yaml.safe_load(template_content)
|
||||
template['template_id'] = template_file
|
||||
templates.append(template)
|
||||
|
||||
return templates
|
||||
|
||||
@classmethod
|
||||
@@ -546,7 +545,7 @@ class ResourceTemplates(object):
|
||||
if getattr(cls, 'template_dir_name', None):
|
||||
dirname = os.path.join('templates', cls.template_dir_name)
|
||||
if not resource_isdir(__name__, dirname):
|
||||
log.warning("No resource directory {dir} found when loading {cls_name} templates".format(
|
||||
log.warning(u"No resource directory {dir} found when loading {cls_name} templates".format(
|
||||
dir=dirname,
|
||||
cls_name=cls.__name__,
|
||||
))
|
||||
|
||||
@@ -677,5 +677,5 @@ def _statsd_tag(course_title):
|
||||
"""
|
||||
Calculate the tag we will use for DataDog.
|
||||
"""
|
||||
tag = "course_email:{0}".format(course_title)
|
||||
tag = u"course_email:{0}".format(course_title)
|
||||
return tag[:200]
|
||||
|
||||
@@ -343,7 +343,7 @@ def _dispatch(table, action, user, obj):
|
||||
action)
|
||||
return result
|
||||
|
||||
raise ValueError("Unknown action for object type '{0}': '{1}'".format(
|
||||
raise ValueError(u"Unknown action for object type '{0}': '{1}'".format(
|
||||
type(obj), action))
|
||||
|
||||
|
||||
|
||||
@@ -321,10 +321,10 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
org, course_num, run = course_id.split("/")
|
||||
|
||||
tags = [
|
||||
"org:{0}".format(org),
|
||||
"course:{0}".format(course_num),
|
||||
"run:{0}".format(run),
|
||||
"score_bucket:{0}".format(score_bucket)
|
||||
u"org:{0}".format(org),
|
||||
u"course:{0}".format(course_num),
|
||||
u"run:{0}".format(run),
|
||||
u"score_bucket:{0}".format(score_bucket)
|
||||
]
|
||||
|
||||
if grade_bucket_type is not None:
|
||||
@@ -443,7 +443,7 @@ def get_module_for_descriptor_internal(user, descriptor, field_data_cache, cours
|
||||
make_psychometrics_data_update_handler(course_id, user, descriptor.location.url())
|
||||
)
|
||||
|
||||
system.set('user_is_staff', has_access(user, descriptor.location, 'staff', course_id))
|
||||
system.set(u'user_is_staff', has_access(user, descriptor.location, u'staff', course_id))
|
||||
|
||||
# make an ErrorDescriptor -- assuming that the descriptor's system is ok
|
||||
if has_access(user, descriptor.location, 'staff', course_id):
|
||||
|
||||
@@ -238,7 +238,7 @@ def index(request, course_id, chapter=None, section=None,
|
||||
registered = registered_for_course(course, user)
|
||||
if not registered:
|
||||
# TODO (vshnayder): do course instructors need to be registered to see course?
|
||||
log.debug('User %s tried to view course %s but is not enrolled' % (user, course.location.url()))
|
||||
log.debug(u'User {0} tried to view course {1} but is not enrolled'.format(user, course.location.url()))
|
||||
return redirect(reverse('about_course', args=[course.id]))
|
||||
|
||||
masq = setup_masquerade(request, staff_access)
|
||||
@@ -249,8 +249,8 @@ def index(request, course_id, chapter=None, section=None,
|
||||
|
||||
course_module = get_module_for_descriptor(user, request, course, field_data_cache, course.id)
|
||||
if course_module is None:
|
||||
log.warning('If you see this, something went wrong: if we got this'
|
||||
' far, should have gotten a course module for this user')
|
||||
log.warning(u'If you see this, something went wrong: if we got this'
|
||||
u' far, should have gotten a course module for this user')
|
||||
return redirect(reverse('about_course', args=[course.id]))
|
||||
|
||||
if chapter is None:
|
||||
@@ -424,9 +424,9 @@ def jump_to(request, course_id, location):
|
||||
try:
|
||||
(course_id, chapter, section, position) = path_to_location(modulestore(), course_id, location)
|
||||
except ItemNotFoundError:
|
||||
raise Http404("No data at this location: {0}".format(location))
|
||||
raise Http404(u"No data at this location: {0}".format(location))
|
||||
except NoPathToItem:
|
||||
raise Http404("This location is not in any class: {0}".format(location))
|
||||
raise Http404(u"This location is not in any class: {0}".format(location))
|
||||
|
||||
# choose the appropriate view (and provide the necessary args) based on the
|
||||
# args provided by the redirect.
|
||||
|
||||
@@ -15,7 +15,8 @@ def cached_has_permission(user, permission, course_id=None):
|
||||
Call has_permission if it's not cached. A change in a user's role or
|
||||
a role's permissions will only become effective after CACHE_LIFESPAN seconds.
|
||||
"""
|
||||
key = "permission_%d_%s_%s" % (user.id, str(course_id), permission)
|
||||
key = u"permission_{user_id:d}_{course_id}_{permission}".format(
|
||||
user_id=user.id, course_id=course_id, permission=permission)
|
||||
val = CACHE.get(key, None)
|
||||
if val not in [True, False]:
|
||||
val = has_permission(user, permission, course_id=course_id)
|
||||
|
||||
@@ -173,7 +173,7 @@ def instructor_dashboard(request, course_id):
|
||||
|
||||
# complete the url using information about the current course:
|
||||
(org, course_name, _) = course_id.split("/")
|
||||
return "i4x://" + org + "/" + course_name + "/" + urlname
|
||||
return u"i4x://{org}/{name}/{url}".format(org=org, name=course_name, url=urlname)
|
||||
|
||||
def get_student_from_identifier(unique_student_identifier):
|
||||
"""Gets a student object using either an email address or username"""
|
||||
@@ -782,7 +782,7 @@ def instructor_dashboard(request, course_id):
|
||||
logs and swallows errors.
|
||||
"""
|
||||
url = settings.ANALYTICS_SERVER_URL + \
|
||||
"get?aname={}&course_id={}&apikey={}".format(analytics_name,
|
||||
u"get?aname={}&course_id={}&apikey={}".format(analytics_name,
|
||||
course_id,
|
||||
settings.ANALYTICS_API_KEY)
|
||||
try:
|
||||
|
||||
@@ -66,7 +66,7 @@ def staff_grading_notifications(course, user):
|
||||
def peer_grading_notifications(course, user):
|
||||
system = LmsModuleSystem(
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -115,7 +115,7 @@ def combined_notifications(course, user):
|
||||
#Set up return values so that we can return them for error cases
|
||||
pending_grading = False
|
||||
img_path = ""
|
||||
notifications={}
|
||||
notifications = {}
|
||||
notification_dict = {'pending_grading': pending_grading, 'img_path': img_path, 'response': notifications}
|
||||
|
||||
#We don't want to show anonymous users anything.
|
||||
@@ -126,7 +126,7 @@ def combined_notifications(course, user):
|
||||
system = LmsModuleSystem(
|
||||
static_url="/static",
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -159,7 +159,7 @@ def combined_notifications(course, user):
|
||||
#Non catastrophic error, so no real action
|
||||
#This is a dev_facing_error
|
||||
log.exception(
|
||||
"Problem with getting notifications from controller query service for course {0} user {1}.".format(
|
||||
u"Problem with getting notifications from controller query service for course {0} user {1}.".format(
|
||||
course_id, student_id))
|
||||
|
||||
if pending_grading:
|
||||
@@ -185,7 +185,7 @@ def set_value_in_cache(student_id, course_id, notification_type, value):
|
||||
|
||||
|
||||
def create_key_name(student_id, course_id, notification_type):
|
||||
key_name = "{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id,
|
||||
key_name = u"{prefix}{type}_{course}_{student}".format(prefix=KEY_PREFIX, type=notification_type, course=course_id,
|
||||
student=student_id)
|
||||
return key_name
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ class MockStaffGradingService(object):
|
||||
'min_for_ml': 10})
|
||||
]})
|
||||
|
||||
|
||||
def save_grade(self, course_id, grader_id, submission_id, score, feedback, skipped, rubric_scores,
|
||||
submission_flagged):
|
||||
return self.get_next(course_id, 'fake location', grader_id)
|
||||
@@ -81,7 +80,7 @@ class StaffGradingService(GradingService):
|
||||
config['system'] = LmsModuleSystem(
|
||||
static_url='/static',
|
||||
track_function=None,
|
||||
get_module = None,
|
||||
get_module=None,
|
||||
render_template=render_to_string,
|
||||
replace_urls=None,
|
||||
)
|
||||
@@ -93,7 +92,6 @@ class StaffGradingService(GradingService):
|
||||
self.get_problem_list_url = self.url + '/get_problem_list/'
|
||||
self.get_notifications_url = self.url + "/get_notifications/"
|
||||
|
||||
|
||||
def get_problem_list(self, course_id, grader_id):
|
||||
"""
|
||||
Get the list of problems for a given course.
|
||||
@@ -113,7 +111,6 @@ class StaffGradingService(GradingService):
|
||||
params = {'course_id': course_id, 'grader_id': grader_id}
|
||||
return self.get(self.get_problem_list_url, params)
|
||||
|
||||
|
||||
def get_next(self, course_id, location, grader_id):
|
||||
"""
|
||||
Get the next thing to grade.
|
||||
@@ -137,7 +134,6 @@ class StaffGradingService(GradingService):
|
||||
'grader_id': grader_id})
|
||||
return json.dumps(self._render_rubric(response))
|
||||
|
||||
|
||||
def save_grade(self, course_id, grader_id, submission_id, score, feedback, skipped, rubric_scores,
|
||||
submission_flagged):
|
||||
"""
|
||||
|
||||
@@ -35,7 +35,7 @@ def quote_slashes(text):
|
||||
';;'. By making the escape sequence fixed length, and escaping
|
||||
identifier character ';', we are able to reverse the escaping.
|
||||
"""
|
||||
return re.sub(r'[;/]', _quote_slashes, text)
|
||||
return re.sub(ur'[;/]', _quote_slashes, text)
|
||||
|
||||
|
||||
def _unquote_slashes(match):
|
||||
@@ -84,7 +84,7 @@ def handler_url(course_id, block, handler, suffix='', query='', thirdparty=False
|
||||
|
||||
url = reverse(view_name, kwargs={
|
||||
'course_id': course_id,
|
||||
'usage_id': quote_slashes(str(block.scope_ids.usage_id)),
|
||||
'usage_id': quote_slashes(unicode(block.scope_ids.usage_id).encode('utf-8')),
|
||||
'handler': handler,
|
||||
'suffix': suffix,
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user