From fb7d597554d4b549a7d72bc41ca6360977217de8 Mon Sep 17 00:00:00 2001 From: Farhanah Sheets Date: Mon, 5 Nov 2018 16:35:35 -0500 Subject: [PATCH 1/3] unicode messages developer and user messages --- lms/djangoapps/courseware/access_response.py | 23 ++++++++++---------- 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/lms/djangoapps/courseware/access_response.py b/lms/djangoapps/courseware/access_response.py index 0784ed8923..415781757d 100644 --- a/lms/djangoapps/courseware/access_response.py +++ b/lms/djangoapps/courseware/access_response.py @@ -124,12 +124,11 @@ class StartDateError(AccessError): def __init__(self, start_date): error_code = "course_not_started" if start_date == DEFAULT_START_DATE: - developer_message = "Course has not started" - user_message = _("Course has not started") + developer_message = u"Course has not started" + user_message = _(u"Course has not started") else: - developer_message = "Course does not start until {}".format(start_date) - user_message = _("Course does not start until {}" - .format("{:%B %d, %Y}".format(start_date))) + developer_message = u"Course does not start until {}".format(start_date) + user_message = _(u"Course does not start until {}").format("{:%B %d, %Y}".format(start_date)) super(StartDateError, self).__init__(error_code, developer_message, user_message) @@ -139,8 +138,8 @@ class MilestoneAccessError(AccessError): """ def __init__(self): error_code = "unfulfilled_milestones" - developer_message = "User has unfulfilled milestones" - user_message = _("You have unfulfilled milestones") + developer_message = u"User has unfulfilled milestones" + user_message = _(u"You have unfulfilled milestones") super(MilestoneAccessError, self).__init__(error_code, developer_message, user_message) @@ -151,8 +150,8 @@ class VisibilityError(AccessError): """ def __init__(self): error_code = "not_visible_to_user" - developer_message = "Course is not visible to this user" - user_message = _("You do not have access to this course") + developer_message = u"Course is not visible to this user" + user_message = _(u"You do not have access to this course") super(VisibilityError, self).__init__(error_code, developer_message, user_message) @@ -162,8 +161,8 @@ class MobileAvailabilityError(AccessError): """ def __init__(self): error_code = "mobile_unavailable" - developer_message = "Course is not available on mobile for this user" - user_message = _("You do not have access to this course on a mobile device") + developer_message = u"Course is not available on mobile for this user" + user_message = _(u"You do not have access to this course on a mobile device") super(MobileAvailabilityError, self).__init__(error_code, developer_message, user_message) @@ -192,5 +191,5 @@ class NoAllowedPartitionGroupsError(AccessError): """ def __init__(self, partition, user_message=None, user_fragment=None): error_code = "no_allowed_user_groups" - developer_message = "Group access for {} excludes all students".format(partition.name) + developer_message = u"Group access for {} excludes all students".format(partition.name) super(NoAllowedPartitionGroupsError, self).__init__(error_code, developer_message, user_message) From 040b60c38c1d42999bddb7e0a312e7a17393dde0 Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 5 Nov 2018 22:38:31 -0500 Subject: [PATCH 2/3] Stop swallowing UnicodeEncodeErrors in courseware rendering --- lms/djangoapps/courseware/courses.py | 2 +- lms/djangoapps/courseware/views/index.py | 4 ++-- lms/djangoapps/courseware/views/views.py | 8 +++----- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/lms/djangoapps/courseware/courses.py b/lms/djangoapps/courseware/courses.py index caccff1313..73edd42bad 100644 --- a/lms/djangoapps/courseware/courses.py +++ b/lms/djangoapps/courseware/courses.py @@ -77,7 +77,7 @@ def get_course_by_id(course_key, depth=0): if course: return course else: - raise Http404("Course not found: {}.".format(unicode(course_key))) + raise Http404(u"Course not found: {}.".format(unicode(course_key))) def get_course_with_access(user, action, course_key, depth=0, check_if_enrolled=False, check_survey_complete=True): diff --git a/lms/djangoapps/courseware/views/index.py b/lms/djangoapps/courseware/views/index.py index a9768fc1af..a8af5b970b 100644 --- a/lms/djangoapps/courseware/views/index.py +++ b/lms/djangoapps/courseware/views/index.py @@ -151,7 +151,7 @@ class CoursewareIndex(View): return self.render(request) except Exception as exception: # pylint: disable=broad-except - return CourseTabView.handle_exceptions(request, self.course, exception) + return CourseTabView.handle_exceptions(request, self.course_key, self.course, exception) def _setup_masquerade_for_effective_user(self): """ @@ -315,7 +315,7 @@ class CoursewareIndex(View): if not child: # User may be trying to access a child that isn't live yet if not self._is_masquerading_as_student(): - raise Http404('No {block_type} found with name {url_name}'.format( + raise Http404(u'No {block_type} found with name {url_name}'.format( block_type=block_type, url_name=url_name, )) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 18a5b220ac..599efdc153 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -509,7 +509,7 @@ class CourseTabView(EdxFragmentView): set_custom_metrics_for_course_key(course_key) return super(CourseTabView, self).get(request, course=course, page_context=page_context, **kwargs) except Exception as exception: # pylint: disable=broad-except - return CourseTabView.handle_exceptions(request, course, exception) + return CourseTabView.handle_exceptions(request, course_key, course, exception) @staticmethod def url_to_enroll(course_key): @@ -560,14 +560,12 @@ class CourseTabView(EdxFragmentView): ) @staticmethod - def handle_exceptions(request, course, exception): + def handle_exceptions(request, course_key, course, exception): """ Handle exceptions raised when rendering a view. """ if isinstance(exception, Redirect) or isinstance(exception, Http404): raise - if isinstance(exception, UnicodeEncodeError): - raise Http404("URL contains Unicode characters") if settings.DEBUG: raise user = request.user @@ -576,7 +574,7 @@ class CourseTabView(EdxFragmentView): request.path, getattr(user, 'real_user', user), user, - None if course is None else text_type(course.id), + text_type(course_key), ) try: return render_to_response( From 95252f1a817c735d88b97fff2a72e57f53658afd Mon Sep 17 00:00:00 2001 From: Calen Pennington Date: Mon, 5 Nov 2018 22:45:41 -0500 Subject: [PATCH 3/3] Run caniusepython3.pylint_checker --- lms/djangoapps/courseware/views/views.py | 2 +- pylintrc | 8 +++++--- pylintrc_tweaks | 5 ++++- requirements/edx/development.txt | 12 +++++++----- requirements/edx/testing.in | 1 + requirements/edx/testing.txt | 13 ++++++++----- 6 files changed, 26 insertions(+), 15 deletions(-) diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 599efdc153..33cc4969ee 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -561,7 +561,7 @@ class CourseTabView(EdxFragmentView): @staticmethod def handle_exceptions(request, course_key, course, exception): - """ + u""" Handle exceptions raised when rendering a view. """ if isinstance(exception, Redirect) or isinstance(exception, Http404): diff --git a/pylintrc b/pylintrc index f664b86f3e..33c88dfa0d 100644 --- a/pylintrc +++ b/pylintrc @@ -55,7 +55,7 @@ [MASTER] ignore = ,.git,.tox,migrations,node_modules,.pycharm_helpers persistent = yes -load-plugins = edx_lint.pylint,pylint_django,pylint_celery +load-plugins = edx_lint.pylint,pylint_django,pylint_celery,caniusepython3.pylint_checker init-hook = "import sys; sys.path.extend(['lms/djangoapps', 'cms/djangoapps', 'common/djangoapps'])" [MESSAGES CONTROL] @@ -345,7 +345,9 @@ disable = unpacking-in-except, using-cmp-argument, xrange-builtin, - zip-builtin-not-iterating,,unicode-format-string + zip-builtin-not-iterating, + unicode-format-string, + native-string, [REPORTS] output-format = text @@ -445,4 +447,4 @@ int-import-graph = [EXCEPTIONS] overgeneral-exceptions = Exception -# c8b8d35a9a123f3c2eb3ce0cb466156bab2beedc +# 4285ece9aa125ff8efc6f77ed6d34579e65e2d96 diff --git a/pylintrc_tweaks b/pylintrc_tweaks index 6b4126f96c..e813d8b6ca 100644 --- a/pylintrc_tweaks +++ b/pylintrc_tweaks @@ -2,10 +2,13 @@ [MASTER] ignore+ = ,.git,.tox,migrations,node_modules,.pycharm_helpers init-hook="import sys; sys.path.extend(['lms/djangoapps', 'cms/djangoapps', 'common/djangoapps'])" +load-plugins+=,caniusepython3.pylint_checker [MESSAGES CONTROL] # Disable unicode-format-string until we can agree to turn it on. -disable+ = ,unicode-format-string +disable+ = + unicode-format-string, + native-string, [BASIC] attr-rgx = [a-z_][a-z0-9_]{2,40}$ diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 045ee47e20..4653142f18 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -52,7 +52,7 @@ argh==0.26.2 argparse==1.4.0 asn1crypto==0.24.0 astroid==1.5.3 -atomicwrites==1.2.1 +atomicwrites==1.3.0 attrs==17.4.0 babel==1.3 backports.functools-lru-cache==1.5 @@ -64,6 +64,7 @@ bok-choy==0.9.0 boto3==1.4.8 boto==2.39.0 botocore==1.8.17 +caniusepython3==7.0.0 celery==3.1.25 certifi==2018.11.29 cffi==1.11.5 @@ -84,6 +85,7 @@ decorator==4.3.2 defusedxml==0.5.0 dicttoxml==1.7.4 diff-cover==0.9.8 +distlib==0.2.8 django-appconf==1.0.2 django-babel-underscore==0.5.2 django-babel==0.6.2 @@ -162,7 +164,7 @@ filelock==3.0.10 firebase-token-generator==1.3.2 fixtures==3.0.0 flake8-polyfill==1.0.2 -flake8==3.7.1 +flake8==3.7.4 flask==1.0.2 freezegun==0.3.11 fs-s3fs==0.1.8 @@ -224,7 +226,7 @@ oauth2==1.9.0.post1 oauthlib==2.1.0 openapi-codec==1.3.2 pa11ycrawler==1.6.2 -packaging==19.0 # via sphinx +packaging==19.0 parsel==1.5.1 path.py==8.2.1 pathlib2==2.3.3 @@ -268,7 +270,7 @@ pysqlite==2.8.3 pysrt==1.1.1 pytest-attrib==0.1.3 pytest-cov==2.6.1 -pytest-django==3.4.5 +pytest-django==3.4.6 pytest-forked==1.0.1 pytest-randomly==1.2.3 pytest-xdist==1.26.1 @@ -330,7 +332,7 @@ toml==0.10.0 tox-battery==0.5.1 tox==3.7.0 traceback2==1.4.0 -transifex-client==0.13.5 +transifex-client==0.13.6 twisted==16.6.0 typing==3.6.6 unicodecsv==0.14.1 diff --git a/requirements/edx/testing.in b/requirements/edx/testing.in index cb63e2fe57..2c644b78ae 100644 --- a/requirements/edx/testing.in +++ b/requirements/edx/testing.in @@ -20,6 +20,7 @@ beautifulsoup4 # Library for extracting data from HTML and XML files before_after # Syntactic sugar for mock, only used in one test case, not Python 3 compatible bok-choy # Framework for browser automation tests, based on selenium +caniusepython3 # Library for checking the ability to upgrade to python3 cssselect # Used to extract HTML fragments via CSS selectors in 2 test cases and pyquery ddt # Run a test case multiple times with different input; used in many, many of our tests edx-i18n-tools>=0.4.6 # Commands for developers and translators to extract, compile and validate translations diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index b94cb73c21..ba777092e5 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -49,7 +49,7 @@ argh==0.26.2 argparse==1.4.0 asn1crypto==0.24.0 astroid==1.5.3 # via edx-lint, pylint, pylint-celery -atomicwrites==1.2.1 # via pytest +atomicwrites==1.3.0 # via pytest attrs==17.4.0 babel==1.3 backports.functools-lru-cache==1.5 @@ -61,6 +61,7 @@ bok-choy==0.9.0 boto3==1.4.8 boto==2.39.0 botocore==1.8.17 +caniusepython3==7.0.0 celery==3.1.25 certifi==2018.11.29 cffi==1.11.5 @@ -81,6 +82,7 @@ decorator==4.3.2 defusedxml==0.5.0 dicttoxml==1.7.4 # via moto diff-cover==0.9.8 +distlib==0.2.8 # via caniusepython3 django-appconf==1.0.2 django-babel-underscore==0.5.2 django-babel==0.6.2 @@ -156,13 +158,13 @@ filelock==3.0.10 # via tox firebase-token-generator==1.3.2 fixtures==3.0.0 # via testtools flake8-polyfill==1.0.2 # via radon -flake8==3.7.1 # via flake8-polyfill +flake8==3.7.4 # via flake8-polyfill flask==1.0.2 # via moto freezegun==0.3.11 fs-s3fs==0.1.8 fs==2.0.18 funcsigs==1.0.2 # via pytest -functools32==3.2.3.post2 # via parsel +functools32==3.2.3.post2 # via flake8, parsel future==0.17.1 futures==3.2.0 ; python_version == "2.7" fuzzywuzzy==0.17.0 @@ -216,6 +218,7 @@ oauth2==1.9.0.post1 oauthlib==2.1.0 openapi-codec==1.3.2 pa11ycrawler==1.6.2 +packaging==19.0 # via caniusepython3 parsel==1.5.1 # via scrapy path.py==8.2.1 pathlib2==2.3.3 # via pytest, pytest-django @@ -257,7 +260,7 @@ pysqlite==2.8.3 pysrt==1.1.1 pytest-attrib==0.1.3 pytest-cov==2.6.1 -pytest-django==3.4.5 +pytest-django==3.4.6 pytest-forked==1.0.1 # via pytest-xdist pytest-randomly==1.2.3 pytest-xdist==1.26.1 @@ -315,7 +318,7 @@ toml==0.10.0 # via tox tox-battery==0.5.1 tox==3.7.0 traceback2==1.4.0 # via testtools, unittest2 -transifex-client==0.13.5 +transifex-client==0.13.6 twisted==16.6.0 # via pa11ycrawler, scrapy typing==3.6.6 # via flake8 unicodecsv==0.14.1