diff --git a/.travis.yml b/.travis.yml index 9113a1d4760..eff9a1ab147 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,33 +1,23 @@ language: python cache: pip python: -- 2.7 - 3.5 services: - xvfb env: -- TOXENV=django111-drf37 -- TOXENV=django111-drf38 - TOXENV=django111-drf39 +- TOXENV=django111-drf310 - TOXENV=django111-drflatest -- TOXENV=django20-drf37 -- TOXENV=django20-drf38 - TOXENV=django20-drf39 +- TOXENV=django20-drf310 - TOXENV=django20-drflatest -- TOXENV=django21-drf37 -- TOXENV=django21-drf38 - TOXENV=django21-drf39 +- TOXENV=django21-drf310 - TOXENV=django21-drflatest -- TOXENV=django22-drf37 -- TOXENV=django22-drf38 -- TOXENV=django22-drf39 +- TOXENV=django22-drf310 - TOXENV=django22-drflatest -# DRF 3.9.x is the latest that still supports python 2, -# and we run DRF 3.7 in edx-platform -# TODO: enable these in future, disable old ones above -# https://openedx.atlassian.net/browse/EDUCATOR-4774 - TOXENV=quality - TOXENV=pii_check - TOXENV=version_check @@ -35,41 +25,6 @@ env: - TOXENV=js_tests - TOXENV=js_lint - -matrix: - exclude: - - python: 2.7 - env: TOXENV=django20-drf37 - - python: 2.7 - env: TOXENV=django20-drf38 - - python: 2.7 - env: TOXENV=django20-drf39 - - python: 2.7 - env: TOXENV=django20-drflatest - - python: 2.7 - env: TOXENV=django21-drf37 - - python: 2.7 - env: TOXENV=django21-drf38 - - python: 2.7 - env: TOXENV=django21-drf39 - - python: 2.7 - env: TOXENV=django21-drflatest - - python: 2.7 - env: TOXENV=django22-drf37 - - python: 2.7 - env: TOXENV=django22-drf38 - - python: 2.7 - env: TOXENV=django22-drf39 - - python: 2.7 - env: TOXENV=django22-drflatest - - python: 2.7 - env: TOXENV=version_check - - python: 2.7 - env: TOXENV=js_lint - - python: 2.7 - env: TOXENV=js_tests - - before_install: - export DISPLAY=:99.0 diff --git a/edx_proctoring/__init__.py b/edx_proctoring/__init__.py index 0a6ae788f34..90ed2d7b44a 100644 --- a/edx_proctoring/__init__.py +++ b/edx_proctoring/__init__.py @@ -5,6 +5,6 @@ from __future__ import absolute_import # Be sure to update the version number in edx_proctoring/package.json -__version__ = '2.2.4' +__version__ = '2.2.5' default_app_config = 'edx_proctoring.apps.EdxProctoringConfig' # pylint: disable=invalid-name diff --git a/edx_proctoring/admin.py b/edx_proctoring/admin.py index d2713101fd5..0ba7346232b 100644 --- a/edx_proctoring/admin.py +++ b/edx_proctoring/admin.py @@ -63,7 +63,7 @@ def save_model(self, request, obj, form, change): class ProctoredExamSoftwareSecureReviewForm(forms.ModelForm): """Admin Form to display for reading/updating a Review""" - class Meta(object): + class Meta: """Meta class""" model = ProctoredExamSoftwareSecureReview fields = '__all__' @@ -104,7 +104,7 @@ def queryset(self, request, queryset): if self.value() == 'all_unreviewed': return queryset.filter(reviewed_by__isnull=True) - elif self.value() == 'all_unreviewed_failures': + if self.value() == 'all_unreviewed_failures': return queryset.filter(reviewed_by__isnull=True, review_status='Suspicious') return queryset @@ -365,7 +365,7 @@ class ProctoredExamAttemptForm(forms.ModelForm): Admin Form to display for reading/updating a Proctored Exam Attempt """ - class Meta(object): + class Meta: """ Meta class """ model = ProctoredExamStudentAttempt fields = '__all__' diff --git a/edx_proctoring/api.py b/edx_proctoring/api.py index 8655a860162..b0f9e05700d 100644 --- a/edx_proctoring/api.py +++ b/edx_proctoring/api.py @@ -817,8 +817,7 @@ def update_attempt_status(exam_id, user_id, to_status, if exam_attempt_obj is None: if raise_if_not_found: raise StudentExamAttemptDoesNotExistsException('Error. Trying to look up an exam that does not exist.') - else: - return + return from_status = exam_attempt_obj.status @@ -1650,7 +1649,7 @@ def _get_timed_exam_view(exam, context, exam_id, user_id, course_id): has_time_expired = False attempt_status = attempt['status'] if attempt else None - has_due_date = True if exam['due_date'] is not None else False + has_due_date = exam['due_date'] is not None if not attempt_status: if is_exam_passed_due(exam, user=user_id): student_view_template = 'timed_exam/expired.html' @@ -1749,7 +1748,7 @@ def _get_proctored_exam_context(exam, attempt, user_id, course_id, is_practice_e """ Common context variables for the Proctored and Practice exams' templates. """ - has_due_date = True if exam['due_date'] is not None else False + has_due_date = exam['due_date'] is not None attempt_time = attempt.get('allowed_time_limit_mins', None) if attempt else None if not attempt_time: diff --git a/edx_proctoring/apps.py b/edx_proctoring/apps.py index 255efc6ec64..9efe5a873c5 100644 --- a/edx_proctoring/apps.py +++ b/edx_proctoring/apps.py @@ -115,7 +115,7 @@ def ready(self): """ Loads the available proctoring backends """ - from edx_proctoring import signals # pylint: disable=unused-variable + from edx_proctoring import signals # pylint: disable=unused-import config = settings.PROCTORING_BACKENDS self.backends = {} # pylint: disable=W0201 diff --git a/edx_proctoring/backends/__init__.py b/edx_proctoring/backends/__init__.py index 1a71b856d8a..da092a053ca 100644 --- a/edx_proctoring/backends/__init__.py +++ b/edx_proctoring/backends/__init__.py @@ -16,6 +16,6 @@ def get_backend_provider(exam=None, name=None): if 'is_proctored' in exam and not exam['is_proctored']: # timed exams don't have a backend return None - elif exam['backend']: + if exam['backend']: name = exam['backend'] return apps.get_app_config('edx_proctoring').get_backend(name=name) diff --git a/edx_proctoring/backends/tests/test_backend.py b/edx_proctoring/backends/tests/test_backend.py index 12e1dfc2b97..114d6e4b85f 100644 --- a/edx_proctoring/backends/tests/test_backend.py +++ b/edx_proctoring/backends/tests/test_backend.py @@ -43,7 +43,7 @@ def register_exam_attempt(self, exam, context): """ if self.attempt_error: raise BackendProviderOnboardingException(self.attempt_error) - elif self.no_attempt_id_error: + if self.no_attempt_id_error: raise BackendProviderSentNoAttemptID(self.no_attempt_id_error, http_status=200) return 'testexternalid' @@ -107,9 +107,8 @@ def get_instructor_url(self, course_id, user, exam_id=None, attempt_id=None, sho def retire_user(self, user_id): if self.last_retire_user: raise BackendProviderCannotRetireUser(user_id) - else: - self.last_retire_user = user_id - return True + self.last_retire_user = user_id + return True class PassthroughBackendProvider(ProctoringBackendProvider): diff --git a/edx_proctoring/backends/tests/test_rest.py b/edx_proctoring/backends/tests/test_rest.py index e9301f766e0..5aafcd810a4 100644 --- a/edx_proctoring/backends/tests/test_rest.py +++ b/edx_proctoring/backends/tests/test_rest.py @@ -107,7 +107,7 @@ def test_get_attempt(self): ) external_attempt = self.provider.get_attempt(attempt) self.assertEqual(external_attempt, attempt) - self.assertEqual(responses.calls[1].request.headers['Accept-Language'], 'en-us') + self.assertEqual(responses.calls[-1].request.headers['Accept-Language'], 'en-us') @responses.activate def test_get_attempt_i18n(self): @@ -127,7 +127,7 @@ def test_get_attempt_i18n(self): with translation.override('es'): external_attempt = self.provider.get_attempt(attempt) self.assertEqual(external_attempt, attempt) - self.assertEqual(responses.calls[1].request.headers['Accept-Language'], 'es;en-us') + self.assertEqual(responses.calls[-1].request.headers['Accept-Language'], 'es;en-us') @responses.activate def test_on_exam_saved(self): @@ -150,7 +150,7 @@ def test_create_exam_with_defaults(self): ) self.backend_exam.pop('external_id') external_id = provider.on_exam_saved(self.backend_exam) - request = json.loads(responses.calls[1].request.body.decode('utf-8')) + request = json.loads(responses.calls[-1].request.body.decode('utf-8')) self.assertEqual(external_id, 'abcdefg') self.assertTrue(request['rules']['allow_grok']) @@ -189,7 +189,7 @@ def test_register_exam_attempt(self): status=200 ) attempt_external_id = self.provider.register_exam_attempt(self.backend_exam, self.register_exam_context) - request = json.loads(responses.calls[1].request.body.decode('utf-8')) + request = json.loads(responses.calls[-1].request.body.decode('utf-8')) self.assertEqual(attempt_external_id, 2) self.assertEqual(request['status'], 'created') self.assertIn('lms_host', request) diff --git a/edx_proctoring/services.py b/edx_proctoring/services.py index 2647bb78655..9acd81117e0 100644 --- a/edx_proctoring/services.py +++ b/edx_proctoring/services.py @@ -7,7 +7,7 @@ import types -class ProctoringService(object): +class ProctoringService: """ An xBlock service for xBlocks to talk to the Proctoring subsystem. This class basically introspects and exposes all functions in the api libraries, so it is a direct pass through. diff --git a/edx_proctoring/statuses.py b/edx_proctoring/statuses.py index 4b93c0a2e5a..8b97241c16f 100644 --- a/edx_proctoring/statuses.py +++ b/edx_proctoring/statuses.py @@ -6,7 +6,7 @@ from edx_proctoring.exceptions import ProctoredExamBadReviewStatus -class ProctoredExamStudentAttemptStatus(object): +class ProctoredExamStudentAttemptStatus: """ A class to enumerate the various status that an attempt can have @@ -154,7 +154,7 @@ def is_in_progress_status(cls, status): ] -class ReviewStatus(object): +class ReviewStatus: """ Standard review statuses """ @@ -173,7 +173,7 @@ def validate(cls, status): return True -class SoftwareSecureReviewStatus(object): +class SoftwareSecureReviewStatus: """ These are the valid review statuses from SoftwareSecure diff --git a/edx_proctoring/tests/test_services.py b/edx_proctoring/tests/test_services.py index c9cd94e8580..558631a2da7 100644 --- a/edx_proctoring/tests/test_services.py +++ b/edx_proctoring/tests/test_services.py @@ -18,7 +18,7 @@ from edx_proctoring.services import ProctoringService -class MockCreditService(object): +class MockCreditService: """ Simple mock of the Credit Service """ @@ -117,7 +117,7 @@ def get_credit_state(self, user_id, course_key, return_course_info=False): # py return None -class MockInstructorService(object): +class MockInstructorService: """ Simple mock of the Instructor Service """ @@ -176,21 +176,21 @@ def test_singleton(self): self.assertIs(service1, service2) -class MockGrade(object): +class MockGrade: """Fake PersistentSubsectionGrade instance.""" def __init__(self, earned_all=0.0, earned_graded=0.0): self.earned_all = earned_all self.earned_graded = earned_graded -class MockGradeOverride(object): +class MockGradeOverride: """Fake PersistentSubsectionGradeOverride instance.""" def __init__(self, earned_all=0.0, earned_graded=0.0): self.earned_all_override = earned_all self.earned_graded_override = earned_graded -class MockGeneratedCertificate(object): +class MockGeneratedCertificate: """Fake GeneratedCertificate instance.""" def __init__(self): self.verify_uuid = 'test_verify_uuid' @@ -210,7 +210,7 @@ def mock_invalidate(self): self.status = 'unavailable' -class MockGradesService(object): +class MockGradesService: """ Simple mock of the Grades Service """ @@ -264,7 +264,7 @@ def should_override_grade_on_rejected_exam(self, course_key): return self.rejected_exam_overrides_grade -class MockCertificateService(object): +class MockCertificateService: """ mock Certificate Service """ diff --git a/edx_proctoring/tests/utils.py b/edx_proctoring/tests/utils.py index b7a792d936e..7eeadf1aa2a 100644 --- a/edx_proctoring/tests/utils.py +++ b/edx_proctoring/tests/utils.py @@ -88,7 +88,6 @@ def emit(self, name=None, data=None): """ Overload this method to do nothing """ - pass class ProctoredExamTestCase(LoggedInTestCase): diff --git a/edx_proctoring/views.py b/edx_proctoring/views.py index 7e034561f79..bed2b3f23f7 100644 --- a/edx_proctoring/views.py +++ b/edx_proctoring/views.py @@ -97,26 +97,25 @@ def wrapped(request, *args, **kwargs): # pylint: disable=missing-docstring attempt_id = kwargs.get('attempt_id', None) if request.user.is_staff: return func(request, *args, **kwargs) - else: - if course_id is None: - if exam_id is not None: - exam = ProctoredExam.get_exam_by_id(exam_id) - course_id = exam.course_id - elif attempt_id is not None: - exam_attempt = ProctoredExamStudentAttempt.objects.get_exam_attempt_by_id(attempt_id) - course_id = exam_attempt.proctored_exam.course_id - else: - response_message = _("could not determine the course_id") - return Response( - status=status.HTTP_403_FORBIDDEN, - data={"detail": response_message} - ) - if instructor_service.is_course_staff(request.user, course_id): - return func(request, *args, **kwargs) - return Response( - status=status.HTTP_403_FORBIDDEN, - data={"detail": _("Must be a Staff User to Perform this request.")} - ) + if course_id is None: + if exam_id is not None: + exam = ProctoredExam.get_exam_by_id(exam_id) + course_id = exam.course_id + elif attempt_id is not None: + exam_attempt = ProctoredExamStudentAttempt.objects.get_exam_attempt_by_id(attempt_id) + course_id = exam_attempt.proctored_exam.course_id + else: + response_message = _("could not determine the course_id") + return Response( + status=status.HTTP_403_FORBIDDEN, + data={"detail": response_message} + ) + if instructor_service.is_course_staff(request.user, course_id): + return func(request, *args, **kwargs) + return Response( + status=status.HTTP_403_FORBIDDEN, + data={"detail": _("Must be a Staff User to Perform this request.")} + ) return wrapped @@ -329,31 +328,30 @@ def get(self, request, attempt_id): ) ) raise StudentExamAttemptDoesNotExistsException(err_msg) - else: - # make sure the the attempt belongs to the calling user_id - if attempt['user']['id'] != request.user.id: - err_msg = ( - u'Attempted to access attempt_id {attempt_id} but ' - u'does not have access to it.'.format( - attempt_id=attempt_id - ) + # make sure the the attempt belongs to the calling user_id + if attempt['user']['id'] != request.user.id: + err_msg = ( + u'Attempted to access attempt_id {attempt_id} but ' + u'does not have access to it.'.format( + attempt_id=attempt_id ) - raise ProctoredExamPermissionDenied(err_msg) + ) + raise ProctoredExamPermissionDenied(err_msg) - # add in the computed time remaining as a helper - time_remaining_seconds = get_time_remaining_for_attempt(attempt) + # add in the computed time remaining as a helper + time_remaining_seconds = get_time_remaining_for_attempt(attempt) - attempt['time_remaining_seconds'] = time_remaining_seconds + attempt['time_remaining_seconds'] = time_remaining_seconds - accessibility_time_string = _(u'you have {remaining_time} remaining').format( - remaining_time=humanized_time(int(round(time_remaining_seconds / 60.0, 0)))) + accessibility_time_string = _(u'you have {remaining_time} remaining').format( + remaining_time=humanized_time(int(round(time_remaining_seconds / 60.0, 0)))) - # special case if we are less than a minute, since we don't produce - # text translations of granularity at the seconds range - if time_remaining_seconds < 60: - accessibility_time_string = _(u'you have less than a minute remaining') + # special case if we are less than a minute, since we don't produce + # text translations of granularity at the seconds range + if time_remaining_seconds < 60: + accessibility_time_string = _(u'you have less than a minute remaining') - attempt['accessibility_time_string'] = accessibility_time_string + attempt['accessibility_time_string'] = accessibility_time_string return Response(attempt) def put(self, request, attempt_id): @@ -804,7 +802,7 @@ def post(self, request, external_id): # pylint: disable=unused-argument return Response(data='OK') -class BaseReviewCallback(object): +class BaseReviewCallback: """ Base class for review callbacks. make_review handles saving reviews and review comments. @@ -1034,8 +1032,7 @@ def get(self, request, course_id, exam_id=None): exam_backend_name ) return Response(data=error_message, status=400) - else: - existing_backend_name = exam_backend_name + existing_backend_name = exam_backend_name if not exam: return Response( diff --git a/package.json b/package.json index 7ebb03ae09d..61f442d6f70 100644 --- a/package.json +++ b/package.json @@ -2,7 +2,7 @@ "name": "@edx/edx-proctoring", "//": "Be sure to update the version number in edx_proctoring/__init__.py", "//": "Note that the version format is slightly different than that of the Python version when using prereleases.", - "version": "2.2.4", + "version": "2.2.5", "main": "edx_proctoring/static/index.js", "repository": { "type": "git", diff --git a/requirements/base.in b/requirements/base.in index dc8789c9f48..a19e392de57 100644 --- a/requirements/base.in +++ b/requirements/base.in @@ -6,7 +6,7 @@ Django>=1.11 django-model-utils djangorestframework django-ipware>=1.1.0 -jsonfield>=2.0.2 +jsonfield2 pytz>=2018 pycryptodomex>=3.4.7 django-crum @@ -21,3 +21,4 @@ edx-opaque-keys>=0.4 edx-drf-extensions edx-rest-api-client>=1.9.2 edx-when>=0.1.3 + diff --git a/requirements/base.txt b/requirements/base.txt index ec78c5d905a..4e112921e12 100644 --- a/requirements/base.txt +++ b/requirements/base.txt @@ -5,28 +5,26 @@ # make upgrade # appdirs==1.4.3 # via fs -backports.os==0.1.1 # via fs certifi==2019.11.28 # via requests chardet==3.0.4 # via requests django-crum==0.7.5 django-ipware==2.1.0 django-model-utils==3.2.0 -django-waffle==0.18.0 +django-waffle==0.19.0 django-webpack-loader==0.6.0 django==1.11.27 djangorestframework-jwt==1.11.0 # via edx-drf-extensions -djangorestframework==3.9.4 ; python_version == "2.7" -edx-django-utils==2.0.2 # via edx-drf-extensions +djangorestframework==3.11.0 +edx-django-utils==2.0.3 # via edx-drf-extensions, edx-rest-api-client edx-drf-extensions==2.4.5 edx-opaque-keys==2.0.1 -edx-rest-api-client==1.9.2 +edx-rest-api-client==3.0.2 edx-when==0.5.2 -enum34==1.1.6 # via fs event-tracking==0.3.0 fs==2.4.11 # via xblock -future==0.18.2 # via backports.os, pyjwkest +future==0.18.2 # via pyjwkest idna==2.8 # via requests -jsonfield==2.0.2 +jsonfield2==3.0.3 lxml==4.4.2 # via xblock markupsafe==1.1.1 # via xblock newrelic==5.4.1.134 # via edx-django-utils @@ -35,21 +33,21 @@ psutil==1.2.1 # via edx-django-utils, edx-drf-extensions pycryptodomex==3.9.4 pyjwkest==1.3.2 # via edx-drf-extensions pyjwt==1.7.1 # via djangorestframework-jwt, edx-rest-api-client -pymongo==3.10.0 # via edx-opaque-keys, event-tracking +pymongo==3.10.1 # via edx-opaque-keys, event-tracking python-dateutil==2.8.1 pytz==2019.3 -pyyaml==5.2 # via xblock +pyyaml==5.3 # via xblock requests==2.22.0 # via edx-drf-extensions, edx-rest-api-client, pyjwkest, slumber rest-condition==1.0.3 # via edx-drf-extensions -rules==2.1 +rules==2.2 semantic-version==2.8.4 # via edx-drf-extensions -six==1.13.0 # via edx-drf-extensions, edx-opaque-keys, event-tracking, fs, pyjwkest, python-dateutil, stevedore, xblock +six==1.14.0 # via django-waffle, edx-drf-extensions, edx-opaque-keys, event-tracking, fs, pyjwkest, python-dateutil, stevedore, xblock slumber==0.7.1 # via edx-rest-api-client stevedore==1.31.0 # via edx-opaque-keys typing==3.7.4.1 # via fs -urllib3==1.25.7 # via requests +urllib3==1.25.8 # via requests web-fragments==0.3.1 # via xblock -webob==1.8.5 # via xblock +webob==1.8.6 # via xblock xblock==1.2.9 # via edx-when # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 84d31eca6d8..516b607840b 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -37,3 +37,6 @@ twine==1.15.0 ; python_version == "2.7" # django-model-utils==4.0.0 version dropped the support for Django 1.11 and Python 2.7 and dropped usage of six django-model-utils<4.0.0 + +# jsonfield2 > 3.0.3 dropped support for python 3.5 +jsonfield2==3.0.3 diff --git a/requirements/dev.txt b/requirements/dev.txt index ba225590f80..622401a2a3c 100644 --- a/requirements/dev.txt +++ b/requirements/dev.txt @@ -5,73 +5,65 @@ # make upgrade # argparse==1.4.0 # via caniusepython3 -astroid==1.6.6 # via pylint, pylint-celery -backports.functools-lru-cache==1.6.1 # via astroid, caniusepython3, isort, pylint -backports.os==0.1.1 # via path.py +astroid==2.3.3 # via pylint, pylint-celery +backports.functools-lru-cache==1.6.1 # via caniusepython3 bleach==3.1.0 # via readme-renderer caniusepython3==7.2.0 certifi==2019.11.28 # via requests chardet==3.0.4 # via requests click-log==0.3.2 # via edx-lint click==7.0 # via click-log, edx-lint, pip-tools -configparser==4.0.2 # via importlib-metadata, pydocstyle, pylint -contextlib2==0.6.0.post1 # via importlib-metadata -diff-cover==2.5.0 +diff-cover==2.5.2 distlib==0.3.0 # via caniusepython3 django==1.11.27 -docutils==0.15.2 # via readme-renderer +docutils==0.16 # via readme-renderer edx-i18n-tools==0.5.0 edx-lint==1.4.1 -enum34==1.1.6 # via astroid filelock==3.0.12 # via tox -future==0.18.2 # via backports.os -futures==3.3.0 ; python_version == "2.7" # via caniusepython3, isort idna==2.8 # via requests -importlib-metadata==1.3.0 # via inflect, path.py, pluggy, tox +importlib-metadata==1.4.0 # via inflect, path, pluggy, tox inflect==3.0.2 # via jinja2-pluralize isort==4.3.21 jinja2-pluralize==0.3.0 # via diff-cover -jinja2==2.10.3 # via diff-cover, jinja2-pluralize +jinja2==2.11.0 # via diff-cover, jinja2-pluralize lazy-object-proxy==1.4.3 # via astroid markupsafe==1.1.1 # via jinja2 mccabe==0.6.1 # via pylint -more-itertools==5.0.0 # via zipp -packaging==19.2 # via caniusepython3, tox -path.py==11.5.2 ; python_version == "2.7" -pathlib2==2.3.5 # via importlib-metadata -pip-tools==4.3.0 +packaging==20.1 # via caniusepython3, tox +path.py==12.4.0 +path==13.1.0 # via path.py +pip-tools==4.4.0 pkginfo==1.5.0.1 # via twine pluggy==0.13.1 # via diff-cover, tox polib==1.1.0 # via edx-i18n-tools py==1.8.1 # via tox pycodestyle==2.5.0 -pydocstyle==3.0.0 ; python_version == "2.7" +pydocstyle==5.0.2 pygments==2.5.2 # via diff-cover, readme-renderer pylint-celery==0.3 # via edx-lint -pylint-django==0.11.1 # via edx-lint +pylint-django==2.0.11 # via edx-lint pylint-plugin-utils==0.6 # via pylint-celery, pylint-django -pylint==1.9.5 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils +pylint==2.4.2 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils pyparsing==2.4.6 # via packaging pytz==2019.3 # via django -pyyaml==5.2 # via edx-i18n-tools +pyyaml==5.3 # via edx-i18n-tools readme-renderer==24.0 # via twine requests-toolbelt==0.9.1 # via twine requests==2.22.0 # via caniusepython3, requests-toolbelt, twine -scandir==1.10.0 # via pathlib2 -singledispatch==3.4.0.3 # via astroid, pylint -six==1.13.0 # via astroid, bleach, diff-cover, edx-i18n-tools, edx-lint, packaging, pathlib2, pip-tools, pydocstyle, pylint, readme-renderer, singledispatch, tox +six==1.14.0 # via astroid, bleach, diff-cover, edx-i18n-tools, edx-lint, packaging, pip-tools, readme-renderer, tox snowballstemmer==2.0.0 # via pydocstyle toml==0.10.0 # via tox tox-battery==0.5.1 tox==3.14.3 -tqdm==4.41.0 # via twine -twine==1.15.0 ; python_version == "2.7" -urllib3==1.25.7 # via requests +tqdm==4.42.0 # via twine +twine==1.15.0 +typed-ast==1.4.1 # via astroid +urllib3==1.25.8 # via requests virtualenv==16.7.9 # via tox webencodings==0.5.1 # via bleach -wheel==0.33.6 +wheel==0.34.1 wrapt==1.11.2 # via astroid -zipp==0.6.0 # via importlib-metadata +zipp==1.1.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/requirements/doc.txt b/requirements/doc.txt index 93fd39a0bfb..682e67ebc82 100644 --- a/requirements/doc.txt +++ b/requirements/doc.txt @@ -7,38 +7,36 @@ alabaster==0.7.12 # via sphinx appdirs==1.4.3 # via fs babel==2.8.0 # via sphinx -backports.os==0.1.1 # via fs bleach==3.1.0 # via readme-renderer certifi==2019.11.28 # via requests chardet==3.0.4 # via doc8, requests django-crum==0.7.5 django-ipware==2.1.0 django-model-utils==3.2.0 -django-waffle==0.18.0 +django-waffle==0.19.0 django-webpack-loader==0.6.0 django==1.11.27 djangorestframework-jwt==1.11.0 # via edx-drf-extensions -djangorestframework==3.9.4 ; python_version == "2.7" +djangorestframework==3.11.0 doc8==0.8.0 -docutils==0.15.2 # via doc8, readme-renderer, restructuredtext-lint, sphinx -edx-django-utils==2.0.2 # via edx-drf-extensions +docutils==0.16 # via doc8, readme-renderer, restructuredtext-lint, sphinx +edx-django-utils==2.0.3 # via edx-drf-extensions, edx-rest-api-client edx-drf-extensions==2.4.5 edx-opaque-keys==2.0.1 -edx-rest-api-client==1.9.2 +edx-rest-api-client==3.0.2 edx-sphinx-theme==1.5.0 edx-when==0.5.2 -enum34==1.1.6 # via fs event-tracking==0.3.0 fs==2.4.11 # via xblock -future==0.18.2 # via backports.os, pyjwkest +future==0.18.2 # via pyjwkest idna==2.8 # via requests imagesize==1.2.0 # via sphinx -jinja2==2.10.3 # via sphinx -jsonfield==2.0.2 +jinja2==2.11.0 # via sphinx +jsonfield2==3.0.3 lxml==4.4.2 # via xblock markupsafe==1.1.1 # via jinja2, xblock newrelic==5.4.1.134 # via edx-django-utils -packaging==19.2 # via sphinx +packaging==20.1 # via sphinx pbr==5.4.4 # via stevedore pockets==0.9.1 # via sphinxcontrib-napoleon psutil==1.2.1 # via edx-django-utils, edx-drf-extensions @@ -46,29 +44,29 @@ pycryptodomex==3.9.4 pygments==2.5.2 # via readme-renderer, sphinx pyjwkest==1.3.2 # via edx-drf-extensions pyjwt==1.7.1 # via djangorestframework-jwt, edx-rest-api-client -pymongo==3.10.0 # via edx-opaque-keys, event-tracking +pymongo==3.10.1 # via edx-opaque-keys, event-tracking pyparsing==2.4.6 # via packaging python-dateutil==2.8.1 pytz==2019.3 -pyyaml==5.2 # via xblock +pyyaml==5.3 # via xblock readme-renderer==24.0 requests==2.22.0 # via edx-drf-extensions, edx-rest-api-client, pyjwkest, slumber, sphinx rest-condition==1.0.3 # via edx-drf-extensions restructuredtext-lint==1.3.0 # via doc8 -rules==2.1 +rules==2.2 semantic-version==2.8.4 # via edx-drf-extensions -six==1.13.0 # via bleach, doc8, edx-drf-extensions, edx-opaque-keys, edx-sphinx-theme, event-tracking, fs, packaging, pockets, pyjwkest, python-dateutil, readme-renderer, sphinx, sphinxcontrib-napoleon, stevedore, xblock +six==1.14.0 # via bleach, django-waffle, doc8, edx-drf-extensions, edx-opaque-keys, edx-sphinx-theme, event-tracking, fs, packaging, pockets, pyjwkest, python-dateutil, readme-renderer, sphinx, sphinxcontrib-napoleon, stevedore, xblock slumber==0.7.1 # via edx-rest-api-client snowballstemmer==2.0.0 # via sphinx sphinx==1.8.4 sphinxcontrib-napoleon==0.7 sphinxcontrib-websupport==1.1.2 # via sphinx stevedore==1.31.0 # via doc8, edx-opaque-keys -typing==3.7.4.1 # via fs, sphinx -urllib3==1.25.7 # via requests +typing==3.7.4.1 # via fs +urllib3==1.25.8 # via requests web-fragments==0.3.1 # via xblock webencodings==0.5.1 # via bleach -webob==1.8.5 # via xblock +webob==1.8.6 # via xblock xblock==1.2.9 # via edx-when # The following packages are considered to be unsafe in a requirements file: diff --git a/requirements/quality.txt b/requirements/quality.txt index 5fab8cd2138..6e7027bf8f4 100644 --- a/requirements/quality.txt +++ b/requirements/quality.txt @@ -5,45 +5,42 @@ # make upgrade # argparse==1.4.0 # via caniusepython3 -astroid==1.6.6 # via pylint, pylint-celery -backports.functools-lru-cache==1.6.1 # via astroid, caniusepython3, isort, pylint +astroid==2.3.3 # via pylint, pylint-celery +backports.functools-lru-cache==1.6.1 # via caniusepython3 bleach==3.1.0 # via readme-renderer caniusepython3==7.2.0 certifi==2019.11.28 # via requests chardet==3.0.4 # via requests click-log==0.3.2 # via edx-lint click==7.0 # via click-log, edx-lint -configparser==4.0.2 # via pydocstyle, pylint distlib==0.3.0 # via caniusepython3 django==1.11.27 -docutils==0.15.2 # via readme-renderer +docutils==0.16 # via readme-renderer edx-lint==1.4.1 -enum34==1.1.6 # via astroid -futures==3.3.0 ; python_version == "2.7" # via caniusepython3, isort idna==2.8 # via requests isort==4.3.21 lazy-object-proxy==1.4.3 # via astroid mccabe==0.6.1 # via pylint -packaging==19.2 # via caniusepython3 +packaging==20.1 # via caniusepython3 pkginfo==1.5.0.1 # via twine pycodestyle==2.5.0 -pydocstyle==3.0.0 ; python_version == "2.7" +pydocstyle==5.0.2 pygments==2.5.2 # via readme-renderer pylint-celery==0.3 # via edx-lint -pylint-django==0.11.1 # via edx-lint +pylint-django==2.0.11 # via edx-lint pylint-plugin-utils==0.6 # via pylint-celery, pylint-django -pylint==1.9.5 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils +pylint==2.4.2 # via edx-lint, pylint-celery, pylint-django, pylint-plugin-utils pyparsing==2.4.6 # via packaging pytz==2019.3 # via django readme-renderer==24.0 # via twine requests-toolbelt==0.9.1 # via twine requests==2.22.0 # via caniusepython3, requests-toolbelt, twine -singledispatch==3.4.0.3 # via astroid, pylint -six==1.13.0 # via astroid, bleach, edx-lint, packaging, pydocstyle, pylint, readme-renderer, singledispatch +six==1.14.0 # via astroid, bleach, edx-lint, packaging, readme-renderer snowballstemmer==2.0.0 # via pydocstyle -tqdm==4.41.0 # via twine -twine==1.15.0 ; python_version == "2.7" -urllib3==1.25.7 # via requests +tqdm==4.42.0 # via twine +twine==1.15.0 +typed-ast==1.4.1 # via astroid +urllib3==1.25.8 # via requests webencodings==0.5.1 # via bleach wrapt==1.11.2 # via astroid diff --git a/requirements/test.txt b/requirements/test.txt index 96fa3a4b205..8e3bb673b17 100644 --- a/requirements/test.txt +++ b/requirements/test.txt @@ -6,81 +6,86 @@ # apipkg==1.5 # via execnet appdirs==1.4.3 # via fs -backports.os==0.1.1 # via fs +attrs==19.3.0 # via pytest bok-choy==1.0.1 certifi==2019.11.28 # via requests chardet==3.0.4 # via requests click==7.0 # via code-annotations code-annotations==0.3.3 -cookies==2.2.1 # via responses -coverage==5.0.1 # via pytest-cov +coverage==5.0.3 # via pytest-cov ddt==1.2.2 django-crum==0.7.5 django-ipware==2.1.0 django-model-utils==3.2.0 -django-waffle==0.18.0 +django-waffle==0.19.0 django-webpack-loader==0.6.0 djangorestframework-jwt==1.11.0 # via edx-drf-extensions -edx-django-utils==2.0.2 # via edx-drf-extensions +edx-django-utils==2.0.3 # via edx-drf-extensions, edx-rest-api-client edx-drf-extensions==2.4.5 edx-i18n-tools==0.5.0 edx-opaque-keys==2.0.1 -edx-rest-api-client==1.9.2 +edx-rest-api-client==3.0.2 edx-when==0.5.2 -enum34==1.1.6 # via fs event-tracking==0.3.0 execnet==1.7.1 # via pytest-xdist -freezegun==0.3.12 +freezegun==0.3.14 fs==2.4.11 # via xblock -funcsigs==1.0.2 # via mock -future==0.18.2 # via backports.os, pyjwkest +future==0.18.2 # via pyjwkest httmock==1.3.0 httpretty==0.9.7 idna==2.8 # via requests -jinja2==2.10.3 # via code-annotations -jsonfield==2.0.2 +importlib-metadata==1.4.0 # via path, pluggy, pytest +jinja2==2.11.0 # via code-annotations +jsonfield2==3.0.3 lazy==1.4 # via bok-choy -logilab-common==1.4.4 +logilab-common==1.5.2 lxml==4.4.2 # via xblock markupsafe==1.1.1 # via jinja2, xblock mock==3.0.5 +more-itertools==5.0.0 # via pytest newrelic==5.4.1.134 # via edx-django-utils -path.py==11.5.2 ; python_version == "2.7" # via edx-i18n-tools -pathlib2==2.3.5 # via pytest-django +packaging==20.1 # via pytest +path.py==12.4.0 # via edx-i18n-tools +path==13.1.0 # via path.py +pathlib2==2.3.5 # via pytest pbr==5.4.4 # via stevedore +pluggy==0.13.1 # via pytest polib==1.1.0 # via edx-i18n-tools psutil==1.2.1 # via edx-django-utils, edx-drf-extensions +py==1.8.1 # via pytest pycryptodomex==3.9.4 pyjwkest==1.3.2 # via edx-drf-extensions pyjwt==1.7.1 # via djangorestframework-jwt, edx-rest-api-client -pymongo==3.10.0 # via edx-opaque-keys, event-tracking +pymongo==3.10.1 # via edx-opaque-keys, event-tracking +pyparsing==2.4.6 # via packaging pytest-cov==2.8.1 -pytest-django==3.7.0 +pytest-django==3.8.0 pytest-forked==1.1.3 # via pytest-xdist pytest-xdist==1.31.0 -pytest==4.6.6 ; python_version == "2.7" # via pytest-cov, pytest-django, pytest-forked, pytest-xdist +pytest==5.3.4 # via pytest-cov, pytest-django, pytest-forked, pytest-xdist python-dateutil==2.8.1 python-slugify==4.0.0 # via code-annotations pytz==2019.3 -pyyaml==5.2 # via code-annotations, edx-i18n-tools, xblock +pyyaml==5.3 # via code-annotations, edx-i18n-tools, xblock requests==2.22.0 # via edx-drf-extensions, edx-rest-api-client, httmock, pyjwkest, responses, slumber responses==0.10.9 rest-condition==1.0.3 # via edx-drf-extensions -rules==2.1 -scandir==1.10.0 # via pathlib2 +rules==2.2 selenium==3.141.0 semantic-version==2.8.4 # via edx-drf-extensions -six==1.13.0 # via bok-choy, edx-drf-extensions, edx-i18n-tools, edx-opaque-keys, event-tracking, freezegun, fs, httpretty, logilab-common, mock, pathlib2, pyjwkest, pytest-xdist, python-dateutil, responses, stevedore, xblock +six==1.14.0 # via bok-choy, django-waffle, edx-drf-extensions, edx-i18n-tools, edx-opaque-keys, event-tracking, freezegun, fs, httpretty, mock, packaging, pathlib2, pyjwkest, pytest-xdist, python-dateutil, responses, stevedore, xblock slumber==0.7.1 # via edx-rest-api-client stevedore==1.31.0 # via code-annotations, edx-opaque-keys sure==1.2.7 testfixtures==6.10.3 text-unidecode==1.3 # via python-slugify typing==3.7.4.1 # via fs -urllib3==1.25.7 # via requests, selenium +urllib3==1.25.8 # via requests, selenium +wcwidth==0.1.8 # via pytest web-fragments==0.3.1 # via xblock -webob==1.8.5 # via xblock +webob==1.8.6 # via xblock xblock==1.2.9 # via edx-when +zipp==1.1.0 # via importlib-metadata # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/setup.py b/setup.py index 620452fa9a4..d234c5f0474 100755 --- a/setup.py +++ b/setup.py @@ -78,8 +78,6 @@ def is_requirement(line): 'Intended Audience :: Developers', 'License :: OSI Approved :: GNU Affero General Public License v3 or later (AGPLv3+)', 'Natural Language :: English', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.5', ], packages=[ diff --git a/tox.ini b/tox.ini index c631dda46cf..e0d65360726 100644 --- a/tox.ini +++ b/tox.ini @@ -1,6 +1,6 @@ [tox] envlist = - py{27,35}-django{111}-drf{37,38,39,latest},py{35}-django{20,21,22}-drf{37,38,39,latest}, + py{35}-django{111,20,21,22}-drf{39,310,latest}, docs, quality, version_check, @@ -13,9 +13,8 @@ deps = django20: Django>=2.0,<2.1 django21: Django>=2.1,<2.2 django22: Django>=2.2,<2.3 - drf37: djangorestframework<3.8.0 - drf38: djangorestframework<3.9.0 drf39: djangorestframework<3.10.0 + drf310: djangorestframework<3.11.0 drflatest: djangorestframework -rrequirements/test.txt commands =