From bc30addfb9555cea7f49149073bbd64e3b7b16c3 Mon Sep 17 00:00:00 2001 From: Jay Zoldak Date: Fri, 10 Jan 2014 12:20:28 -0500 Subject: [PATCH] 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. --- cms/djangoapps/contentstore/utils.py | 4 ++-- .../contentstore/views/component.py | 3 +-- cms/djangoapps/contentstore/views/course.py | 8 ++++--- cms/djangoapps/contentstore/views/preview.py | 2 +- cms/static/js/index.js | 4 ++-- cms/templates/unit.html | 2 +- common/djangoapps/cache_toolbox/core.py | 6 +++--- common/djangoapps/course_groups/cohorts.py | 2 +- common/djangoapps/static_replace/__init__.py | 4 ++-- common/djangoapps/student/roles.py | 17 ++++++++------- common/djangoapps/student/views.py | 8 +++---- common/lib/capa/capa/capa_problem.py | 2 +- common/lib/capa/capa/correctmap.py | 2 +- common/lib/capa/capa/xqueue_interface.py | 2 +- .../xmodule/xmodule/contentstore/content.py | 12 ++++++----- .../xmodule/xmodule/modulestore/__init__.py | 21 +++++++++++-------- .../xmodule/modulestore/loc_mapper_store.py | 19 ++++++++--------- .../xmodule/xmodule/modulestore/locator.py | 12 +++++------ .../xmodule/xmodule/modulestore/parsers.py | 7 ++++--- .../xmodule/modulestore/store_utilities.py | 6 +++--- .../xmodule/xmodule/tests/test_conditional.py | 12 +++++------ common/lib/xmodule/xmodule/x_module.py | 5 ++--- lms/djangoapps/bulk_email/tasks.py | 2 +- lms/djangoapps/courseware/access.py | 2 +- lms/djangoapps/courseware/module_render.py | 10 ++++----- lms/djangoapps/courseware/views.py | 10 ++++----- .../django_comment_client/permissions.py | 3 ++- lms/djangoapps/instructor/views/legacy.py | 4 ++-- .../open_ended_notifications.py | 10 ++++----- .../staff_grading_service.py | 6 +----- lms/lib/xblock/runtime.py | 4 ++-- 31 files changed, 107 insertions(+), 104 deletions(-) diff --git a/cms/djangoapps/contentstore/utils.py b/cms/djangoapps/contentstore/utils.py index f5b3196ccb..fbe04186c4 100644 --- a/cms/djangoapps/contentstore/utils.py +++ b/cms/djangoapps/contentstore/utils.py @@ -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 ) diff --git a/cms/djangoapps/contentstore/views/component.py b/cms/djangoapps/contentstore/views/component.py index d466bbe732..8c1bcb7a9d 100644 --- a/cms/djangoapps/contentstore/views/component.py +++ b/cms/djangoapps/contentstore/views/component.py @@ -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, diff --git a/cms/djangoapps/contentstore/views/course.py b/cms/djangoapps/contentstore/views/course.py index 89c5a33db7..e930e33c1a 100644 --- a/cms/djangoapps/contentstore/views/course.py +++ b/cms/djangoapps/contentstore/views/course.py @@ -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')) diff --git a/cms/djangoapps/contentstore/views/preview.py b/cms/djangoapps/contentstore/views/preview.py index 19b351d59c..11bea40f9f 100644 --- a/cms/djangoapps/contentstore/views/preview.py +++ b/cms/djangoapps/contentstore/views/preview.py @@ -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('/?') diff --git a/cms/static/js/index.js b/cms/static/js/index.js index d8a6903763..fff1923f4d 100644 --- a/cms/static/js/index.js +++ b/cms/static/js/index.js @@ -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 ''; }; diff --git a/cms/templates/unit.html b/cms/templates/unit.html index 1151b4c552..04d73d8efd 100644 --- a/cms/templates/unit.html +++ b/cms/templates/unit.html @@ -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=''.format(url=subsection_url), + link_start=u''.format(url=subsection_url), link_end='', )}

diff --git a/common/djangoapps/cache_toolbox/core.py b/common/djangoapps/cache_toolbox/core.py index 9a7be940b8..3321f83d5e 100644 --- a/common/djangoapps/cache_toolbox/core.py +++ b/common/djangoapps/cache_toolbox/core.py @@ -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")) diff --git a/common/djangoapps/course_groups/cohorts.py b/common/djangoapps/course_groups/cohorts.py index d2c7e3a782..c6b93e5634 100644 --- a/common/djangoapps/course_groups/cohorts.py +++ b/common/djangoapps/course_groups/cohorts.py @@ -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 diff --git a/common/djangoapps/static_replace/__init__.py b/common/djangoapps/static_replace/__init__.py index a05129d864..29dcf7455b 100644 --- a/common/djangoapps/static_replace/__init__.py +++ b/common/djangoapps/static_replace/__init__.py @@ -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\\?['"]) # the opening quotes (?P{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 )), diff --git a/common/djangoapps/student/roles.py b/common/djangoapps/student/roles.py index daf3f6ee02..a0783196b5 100644 --- a/common/djangoapps/student/roles.py +++ b/common/djangoapps/student/roles.py @@ -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) diff --git a/common/djangoapps/student/views.py b/common/djangoapps/student/views.py index 007b894900..5ab43a161d 100644 --- a/common/djangoapps/student/views.py +++ b/common/djangoapps/student/views.py @@ -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) diff --git a/common/lib/capa/capa/capa_problem.py b/common/lib/capa/capa/capa_problem.py index f011b3813e..d14af5b0d8 100644 --- a/common/lib/capa/capa/capa_problem.py +++ b/common/lib/capa/capa/capa_problem.py @@ -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". diff --git a/common/lib/capa/capa/correctmap.py b/common/lib/capa/capa/correctmap.py index 2ea4a35c02..df7efee343 100644 --- a/common/lib/capa/capa/correctmap.py +++ b/common/lib/capa/capa/correctmap.py @@ -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, diff --git a/common/lib/capa/capa/xqueue_interface.py b/common/lib/capa/capa/xqueue_interface.py index 270b696f9f..78b9fcd008 100644 --- a/common/lib/capa/capa/xqueue_interface.py +++ b/common/lib/capa/capa/xqueue_interface.py @@ -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 diff --git a/common/lib/xmodule/xmodule/contentstore/content.py b/common/lib/xmodule/xmodule/contentstore/content.py index 61ff0bc192..50e7f5d848 100644 --- a/common/lib/xmodule/xmodule/contentstore/content.py +++ b/common/lib/xmodule/xmodule/contentstore/content.py @@ -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 diff --git a/common/lib/xmodule/xmodule/modulestore/__init__.py b/common/lib/xmodule/xmodule/modulestore/__init__.py index 89b8e80d15..5d241731a7 100644 --- a/common/lib/xmodule/xmodule/modulestore/__init__.py +++ b/common/lib/xmodule/xmodule/modulestore/__init__.py @@ -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]) diff --git a/common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py b/common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py index 7e00abfdac..37853d0789 100644 --- a/common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py +++ b/common/lib/xmodule/xmodule/modulestore/loc_mapper_store.py @@ -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) diff --git a/common/lib/xmodule/xmodule/modulestore/locator.py b/common/lib/xmodule/xmodule/modulestore/locator.py index bde6cee838..2b58797532 100644 --- a/common/lib/xmodule/xmodule/modulestore/locator.py +++ b/common/lib/xmodule/xmodule/modulestore/locator.py @@ -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 '' @@ -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): """ diff --git a/common/lib/xmodule/xmodule/modulestore/parsers.py b/common/lib/xmodule/xmodule/modulestore/parsers.py index f1f49febb4..9d046effdb 100644 --- a/common/lib/xmodule/xmodule/modulestore/parsers.py +++ b/common/lib/xmodule/xmodule/modulestore/parsers.py @@ -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""" (?Pedx://)? @@ -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): diff --git a/common/lib/xmodule/xmodule/modulestore/store_utilities.py b/common/lib/xmodule/xmodule/modulestore/store_utilities.py index a01eb5e5f1..9408dc14fd 100644 --- a/common/lib/xmodule/xmodule/modulestore/store_utilities.py +++ b/common/lib/xmodule/xmodule/modulestore/store_utilities.py @@ -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) diff --git a/common/lib/xmodule/xmodule/tests/test_conditional.py b/common/lib/xmodule/xmodule/tests/test_conditional.py index 74aa83073f..0487194dbc 100644 --- a/common/lib/xmodule/xmodule/tests/test_conditional.py +++ b/common/lib/xmodule/xmodule/tests/test_conditional.py @@ -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) diff --git a/common/lib/xmodule/xmodule/x_module.py b/common/lib/xmodule/xmodule/x_module.py index 51d077c686..9fe208fd04 100644 --- a/common/lib/xmodule/xmodule/x_module.py +++ b/common/lib/xmodule/xmodule/x_module.py @@ -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__, )) diff --git a/lms/djangoapps/bulk_email/tasks.py b/lms/djangoapps/bulk_email/tasks.py index d02045a8be..5b07f49fa5 100644 --- a/lms/djangoapps/bulk_email/tasks.py +++ b/lms/djangoapps/bulk_email/tasks.py @@ -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] diff --git a/lms/djangoapps/courseware/access.py b/lms/djangoapps/courseware/access.py index e5cfc85038..8f78991572 100644 --- a/lms/djangoapps/courseware/access.py +++ b/lms/djangoapps/courseware/access.py @@ -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)) diff --git a/lms/djangoapps/courseware/module_render.py b/lms/djangoapps/courseware/module_render.py index 51f236adc7..207e46f638 100644 --- a/lms/djangoapps/courseware/module_render.py +++ b/lms/djangoapps/courseware/module_render.py @@ -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): diff --git a/lms/djangoapps/courseware/views.py b/lms/djangoapps/courseware/views.py index e60b6c5394..4e0e97c2bc 100644 --- a/lms/djangoapps/courseware/views.py +++ b/lms/djangoapps/courseware/views.py @@ -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. diff --git a/lms/djangoapps/django_comment_client/permissions.py b/lms/djangoapps/django_comment_client/permissions.py index 3c83556a7e..4003dfb460 100644 --- a/lms/djangoapps/django_comment_client/permissions.py +++ b/lms/djangoapps/django_comment_client/permissions.py @@ -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) diff --git a/lms/djangoapps/instructor/views/legacy.py b/lms/djangoapps/instructor/views/legacy.py index ae740ad319..c671b28922 100644 --- a/lms/djangoapps/instructor/views/legacy.py +++ b/lms/djangoapps/instructor/views/legacy.py @@ -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: diff --git a/lms/djangoapps/open_ended_grading/open_ended_notifications.py b/lms/djangoapps/open_ended_grading/open_ended_notifications.py index e99f51283c..9398a11957 100644 --- a/lms/djangoapps/open_ended_grading/open_ended_notifications.py +++ b/lms/djangoapps/open_ended_grading/open_ended_notifications.py @@ -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 diff --git a/lms/djangoapps/open_ended_grading/staff_grading_service.py b/lms/djangoapps/open_ended_grading/staff_grading_service.py index 090b36d13c..81a2eb401c 100644 --- a/lms/djangoapps/open_ended_grading/staff_grading_service.py +++ b/lms/djangoapps/open_ended_grading/staff_grading_service.py @@ -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): """ diff --git a/lms/lib/xblock/runtime.py b/lms/lib/xblock/runtime.py index cb2c033025..74066a6af1 100644 --- a/lms/lib/xblock/runtime.py +++ b/lms/lib/xblock/runtime.py @@ -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, })