diff --git a/.coveragerc b/.coveragerc index 2401b5e4..66133179 100644 --- a/.coveragerc +++ b/.coveragerc @@ -5,6 +5,7 @@ source=edx_exams omit = edx_exams/settings/* edx_exams/conf* + edx_exams/docker_gunicorn_configuration.py *wsgi.py *migrations* *admin.py diff --git a/edx_exams/apps/api/serializers.py b/edx_exams/apps/api/serializers.py index 1d0358cc..12376cfb 100644 --- a/edx_exams/apps/api/serializers.py +++ b/edx_exams/apps/api/serializers.py @@ -25,7 +25,7 @@ class Meta: model = User fields = ( - "id", "username", "email", "lms_user_id" + 'id', 'username', 'email', 'lms_user_id' ) @@ -36,7 +36,7 @@ class ProctoringProviderSerializer(serializers.ModelSerializer): class Meta: model = ProctoringProvider - fields = ["name", "verbose_name", "lti_configuration_id"] + fields = ['name', 'verbose_name', 'lti_configuration_id'] class ExamSerializer(serializers.ModelSerializer): @@ -61,8 +61,8 @@ class Meta: model = Exam fields = ( - "id", "exam_name", "course_id", "content_id", "time_limit_mins", "due_date", "exam_type", - "hide_after_due", "is_active" + 'id', 'exam_name', 'course_id', 'content_id', 'time_limit_mins', 'due_date', 'exam_type', + 'hide_after_due', 'is_active' ) def validate_exam_type(self, value): @@ -71,7 +71,7 @@ def validate_exam_type(self, value): """ valid_exam_types = [exam_type.name for exam_type in EXAM_TYPES] if value not in valid_exam_types: - raise serializers.ValidationError("Must be a valid exam type.") + raise serializers.ValidationError('Must be a valid exam type.') return value @@ -92,8 +92,8 @@ class Meta: model = ExamAttempt fields = ( - "id", "created", "modified", "user", "start_time", "end_time", - "status", "exam", "allowed_time_limit_mins", "attempt_number" + 'id', 'created', 'modified', 'user', 'start_time', 'end_time', + 'status', 'exam', 'allowed_time_limit_mins', 'attempt_number' ) @@ -135,6 +135,6 @@ class Meta: model = ExamAttempt fields = ( - "attempt_id", "attempt_status", "course_id", "exam_type", - "exam_display_name", "exam_url_path", "time_remaining_seconds" + 'attempt_id', 'attempt_status', 'course_id', 'exam_type', + 'exam_display_name', 'exam_url_path', 'time_remaining_seconds' ) diff --git a/edx_exams/apps/api/test_utils/__init__.py b/edx_exams/apps/api/test_utils/__init__.py index 22b42b5b..723de3cf 100644 --- a/edx_exams/apps/api/test_utils/__init__.py +++ b/edx_exams/apps/api/test_utils/__init__.py @@ -57,5 +57,5 @@ def build_jwt_headers(self, user): """ jwt_payload = self.default_payload(user) jwt_token = self.generate_token(jwt_payload) - headers = {"HTTP_AUTHORIZATION": "JWT " + jwt_token} + headers = {'HTTP_AUTHORIZATION': 'JWT ' + jwt_token} return headers diff --git a/edx_exams/apps/api/v1/tests/test_views.py b/edx_exams/apps/api/v1/tests/test_views.py index 82e96803..02dab35e 100644 --- a/edx_exams/apps/api/v1/tests/test_views.py +++ b/edx_exams/apps/api/v1/tests/test_views.py @@ -63,7 +63,7 @@ def patch_api(self, user, data): data = json.dumps(data) headers = self.build_jwt_headers(user) - return self.client.patch(self.url, data, **headers, content_type="application/json") + return self.client.patch(self.url, data, **headers, content_type='application/json') def get_response(self, user, data, expected_response): """ @@ -117,8 +117,8 @@ def test_invalid_data(self): } ] response = self.get_response(self.user, data, 400) - self.assertIn("hide_after_due", response.data["errors"][0]) - self.assertIn("is_active", response.data["errors"][0]) + self.assertIn('hide_after_due', response.data['errors'][0]) + self.assertIn('is_active', response.data['errors'][0]) def test_invalid_exam_type(self): """ @@ -136,7 +136,7 @@ def test_invalid_exam_type(self): } ] response = self.get_response(self.user, data, 400) - self.assertIn("exam_type", response.data["errors"][0]) + self.assertIn('exam_type', response.data['errors'][0]) def test_existing_exam_update(self): """ @@ -287,7 +287,7 @@ def patch_api(self, user, data): data = json.dumps(data) headers = self.build_jwt_headers(user) - return self.client.patch(self.url, data, **headers, content_type="application/json") + return self.client.patch(self.url, data, **headers, content_type='application/json') def test_patch_auth_failures(self): """ @@ -493,7 +493,7 @@ def get_response(self): """ Helper function to make a get request """ - url = reverse("api:v1:proctoring-providers-list") + url = reverse('api:v1:proctoring-providers-list') response = self.client.get(url) return response @@ -578,7 +578,7 @@ def get_exam_access(self, user, url): return self.client.get(url, **headers) def assert_valid_exam_access_token(self, response, user, exam): - token = response.data.get("exam_access_token") + token = response.data.get('exam_access_token') self.assertEqual(unpack_token_for(token, user.lms_user_id).get('course_id'), exam.course_id) self.assertEqual(unpack_token_for(token, user.lms_user_id).get('content_id'), exam.content_id) @@ -818,7 +818,7 @@ def test_expiration_started_exam_attempt_various_times(self, start_delta, curren self.assertEqual(response_status, response.status_code) self.assert_valid_exam_access_token(response, self.user, self.exam) - expiration = response.data.get("exam_access_token_expiration") + expiration = response.data.get('exam_access_token_expiration') default_secs = 60 if is_default: self.assertEqual(expiration, default_secs) @@ -866,7 +866,7 @@ def get_api(self, user): headers = self.build_jwt_headers(user) url = reverse('api:v1:exams-attempt-latest') - return self.client.get(url, **headers, content_type="application/json") + return self.client.get(url, **headers, content_type='application/json') def create_mock_attempt(self, user, status, start_time, allowed_time_limit_mins): """ @@ -1045,7 +1045,7 @@ def put_api(self, user, attempt_id, data): headers = self.build_jwt_headers(user) url = reverse('api:v1:exams-attempt', args=[attempt_id]) - return self.client.put(url, data, **headers, content_type="application/json") + return self.client.put(url, data, **headers, content_type='application/json') def post_api(self, user, data): """ @@ -1055,7 +1055,7 @@ def post_api(self, user, data): headers = self.build_jwt_headers(user) url = reverse('api:v1:exams-attempt') - return self.client.post(url, data, **headers, content_type="application/json") + return self.client.post(url, data, **headers, content_type='application/json') def test_put_user_update_permissions(self): """ diff --git a/edx_exams/apps/api/v1/urls.py b/edx_exams/apps/api/v1/urls.py index c8d734db..4ced72f9 100644 --- a/edx_exams/apps/api/v1/urls.py +++ b/edx_exams/apps/api/v1/urls.py @@ -23,12 +23,12 @@ re_path(fr'configs/course_id/{COURSE_ID_PATTERN}', CourseExamConfigurationsView.as_view(), name='course-exam-config'), - re_path(r"^providers?$", + re_path(r'^providers?$', ProctoringProvidersView.as_view(), - name="proctoring-providers-list",), + name='proctoring-providers-list',), re_path(fr'access_tokens/exam_id/{EXAM_ID_PATTERN}', ExamAccessTokensView.as_view(), - name="exam-access-tokens"), + name='exam-access-tokens'), path('exams/attempt/', ExamAttemptView.as_view(), name='exams-attempt',), diff --git a/edx_exams/apps/api/v1/views.py b/edx_exams/apps/api/v1/views.py index 536c2e62..48e62c70 100644 --- a/edx_exams/apps/api/v1/views.py +++ b/edx_exams/apps/api/v1/views.py @@ -80,7 +80,7 @@ def update_exam(cls, exam_object, fields): exam_object.save() log.info( - "Updated existing exam=%(exam_id)s", + 'Updated existing exam=%(exam_id)s', { 'exam_id': exam_object.id, } @@ -94,7 +94,7 @@ def create_exam(cls, fields): exam = Exam.objects.create(resource_id=str(uuid.uuid4()), **fields) log.info( - "Created new exam=%(exam_id)s", + 'Created new exam=%(exam_id)s', { 'exam_id': exam.id, } @@ -157,8 +157,8 @@ def handle_exams(cls, request_exams_list, course_exams_qs, course_id): path_parameter('course_id', str, 'edX course run ID or external course key'), ], responses={ - 200: "OK", - 400: "Invalid request. See message." + 200: 'OK', + 400: 'Invalid request. See message.' }, summary='Modify exams', description='This endpoint should create new exams, update existing exams, ' @@ -186,7 +186,7 @@ def patch(self, request, course_id): data = {} else: response_status = status.HTTP_400_BAD_REQUEST - data = {"detail": "Invalid data", "errors": serializer.errors} + data = {'detail': 'Invalid data', 'errors': serializer.errors} return Response(status=response_status, data=data) @@ -243,7 +243,7 @@ def patch(self, request, course_id): # check that proctoring provider is in request if 'provider' not in request.data: - error = {"detail": "No proctoring provider name in request."} + error = {'detail': 'No proctoring provider name in request.'} elif request.data.get('provider') is None: provider = None else: @@ -251,7 +251,7 @@ def patch(self, request, course_id): provider = ProctoringProvider.objects.get(name=request.data['provider']) # return 400 if proctoring provider does not exist except ObjectDoesNotExist: - error = {"detail": "Proctoring provider does not exist."} + error = {'detail': 'Proctoring provider does not exist.'} if not error: CourseExamConfiguration.create_or_update(provider, course_id) @@ -325,11 +325,11 @@ def get_response(cls, exam, user): 403 error if access is not granted. """ - claims = {"course_id": exam.course_id, "content_id": exam.content_id} + claims = {'course_id': exam.course_id, 'content_id': exam.content_id} expiration_window = 60 exam_attempt = ExamAttempt.get_current_exam_attempt(user.id, exam.id) - data = {"detail": "Exam access token not granted"} + data = {'detail': 'Exam access token not granted'} grant_access = False response_status = status.HTTP_403_FORBIDDEN @@ -354,9 +354,9 @@ def get_response(cls, exam, user): grant_access, response_status = True, status.HTTP_200_OK if grant_access: - log.info("Creating exam access token") + log.info('Creating exam access token') access_token = sign_token_for(user.lms_user_id, expiration_window, claims) - data = {"exam_access_token": access_token, "exam_access_token_expiration": expiration_window} + data = {'exam_access_token': access_token, 'exam_access_token_expiration': expiration_window} response = Response(status=response_status, data=data) @@ -374,7 +374,7 @@ def get(self, request, exam_id): except ObjectDoesNotExist: response_status = status.HTTP_404_NOT_FOUND return Response(status=response_status, - data={"detail": "Exam does not exist"}) + data={'detail': 'Exam does not exist'}) response = self.get_response(exam, request.user) @@ -512,8 +512,8 @@ def put(self, request, attempt_id): # user should only be able to update their own attempt if attempt.user.id != request.user.id: error_msg = ( - f"user_id={attempt.user.id} attempted to update attempt_id={attempt.id} in " - f"course_id={attempt.exam.course_id} but does not have access to it. (action={action})" + f'user_id={attempt.user.id} attempted to update attempt_id={attempt.id} in ' + f'course_id={attempt.exam.course_id} but does not have access to it. (action={action})' ) error = {'detail': error_msg} return Response(status=status.HTTP_403_FORBIDDEN, data=error) @@ -529,7 +529,7 @@ def put(self, request, attempt_id): to_status = action_mapping.get(action) if to_status: attempt_id = update_attempt_status(attempt_id, to_status) - data = {"exam_attempt_id": attempt_id} + data = {'exam_attempt_id': attempt_id} return Response(data) return Response( diff --git a/edx_exams/apps/core/api.py b/edx_exams/apps/core/api.py index e1853628..129c9f3a 100644 --- a/edx_exams/apps/core/api.py +++ b/edx_exams/apps/core/api.py @@ -96,7 +96,7 @@ def _allow_status_transition(attempt_obj, to_status): illegal_status_transition_msg = ( f'A status transition from "{attempt_obj.status}" to "{to_status}" was attempted ' f'on exam_id={attempt_obj.exam.id} for user_id={attempt_obj.user.id}. This is not ' - f"allowed! (course_id={attempt_obj.exam.course_id})" + f'allowed! (course_id={attempt_obj.exam.course_id})' ) return False, illegal_status_transition_msg return True, '' diff --git a/edx_exams/apps/core/constants.py b/edx_exams/apps/core/constants.py index 59646fad..7b3b90ba 100644 --- a/edx_exams/apps/core/constants.py +++ b/edx_exams/apps/core/constants.py @@ -3,8 +3,8 @@ class Status: """Health statuses.""" - OK = "OK" - UNAVAILABLE = "UNAVAILABLE" + OK = 'OK' + UNAVAILABLE = 'UNAVAILABLE' # Pulled from edx-platform. Will correctly capture both old- and new-style diff --git a/edx_exams/apps/core/middleware.py b/edx_exams/apps/core/middleware.py index 953e2b8e..55bc05a4 100644 --- a/edx_exams/apps/core/middleware.py +++ b/edx_exams/apps/core/middleware.py @@ -20,4 +20,4 @@ def process_request(self, request): # pylint: disable=missing-function-docstrin return if request.COOKIES.get(jwt_cookie_header_payload_name(), None): - request.META[USE_JWT_COOKIE_HEADER] = "true" + request.META[USE_JWT_COOKIE_HEADER] = 'true' diff --git a/edx_exams/apps/core/models.py b/edx_exams/apps/core/models.py index 3768e14f..7ef001e5 100644 --- a/edx_exams/apps/core/models.py +++ b/edx_exams/apps/core/models.py @@ -278,14 +278,14 @@ def create_or_update(cls, provider, course_id): if existing_config: if existing_config.provider == provider: # nothing to be done - log.info(f"Course exam configuration course_id={course_id} already has provider={provider_name}") + log.info(f'Course exam configuration course_id={course_id} already has provider={provider_name}') return count = cls.update_course_config_provider(existing_config, provider) - log.info(f"Updated course exam configuration course_id={course_id} " - + f"to provider={provider_name} and recreated {count} exams") + log.info(f'Updated course exam configuration course_id={course_id} ' + + f'to provider={provider_name} and recreated {count} exams') else: CourseExamConfiguration.objects.create(course_id=course_id, provider=provider) - log.info(f"Created course exam configuration course_id={course_id}, provider={provider_name}") + log.info(f'Created course exam configuration course_id={course_id}, provider={provider_name}') @classmethod def update_course_config_provider(cls, existing_config, new_provider): diff --git a/edx_exams/apps/core/views.py b/edx_exams/apps/core/views.py index 39fa2b33..fdf9a64e 100644 --- a/edx_exams/apps/core/views.py +++ b/edx_exams/apps/core/views.py @@ -39,8 +39,8 @@ class Health(APIView): @schema( parameters=[], responses={ - 200: "OK", - 503: "Service unavailable" + 200: 'OK', + 503: 'Service unavailable' }, summary='Allows a load balancer to verify this service is up.', description='Checks the status of the database connection on which this service relies.' @@ -54,7 +54,7 @@ def get(self, request): try: cursor = connection.cursor() - cursor.execute("SELECT 1") + cursor.execute('SELECT 1') cursor.fetchone() cursor.close() database_status = Status.OK diff --git a/edx_exams/docker_gunicorn_configuration.py b/edx_exams/docker_gunicorn_configuration.py index 3fc195ad..6176d207 100644 --- a/edx_exams/docker_gunicorn_configuration.py +++ b/edx_exams/docker_gunicorn_configuration.py @@ -5,14 +5,15 @@ preload_app = True timeout = 300 -bind = "0.0.0.0:18740" +bind = '0.0.0.0:18740' workers = 2 def pre_request(worker, req): + # pragma: no cover """Log requests before they are processed.""" - worker.log.info("%s %s" % (req.method, req.path)) + worker.log.info('%s %s' % (req.method, req.path)) def close_all_caches(): @@ -51,7 +52,8 @@ def post_fork(server, worker): # pylint: disable=unused-argument def when_ready(server): # pylint: disable=unused-argument """When running in debug mode, run Django's `check` to better match what `manage.py runserver` does.""" + # pragma: no cover from django.conf import settings # lint-amnesty, pylint: disable=import-outside-toplevel from django.core.management import call_command # lint-amnesty, pylint: disable=import-outside-toplevel if settings.DEBUG: - call_command("check") + call_command('check') diff --git a/edx_exams/urls.py b/edx_exams/urls.py index 40e46b7a..ef61ddb9 100644 --- a/edx_exams/urls.py +++ b/edx_exams/urls.py @@ -46,9 +46,9 @@ urlpatterns.append(path('__debug__/', include(debug_toolbar.urls))) api_info = make_api_info( - title="edX Exams API", - version="v0", - description="A REST API for interacting with the edX exams service." + title='edX Exams API', + version='v0', + description='A REST API for interacting with the edX exams service.' ) urlpatterns += make_docs_urls( diff --git a/manage.py b/manage.py index 4bd54446..d79b8be2 100755 --- a/manage.py +++ b/manage.py @@ -9,6 +9,8 @@ PWD = os.path.abspath(os.path.dirname(__file__)) if __name__ == '__main__': + # pylint: disable=inconsistent-quotes + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'edx_exams.settings.local') sys.path.append(PWD) try: diff --git a/pylintrc b/pylintrc index 3e8eec3f..59d776e1 100644 --- a/pylintrc +++ b/pylintrc @@ -2,7 +2,7 @@ # ** DO NOT EDIT THIS FILE ** # *************************** # -# This file was generated by edx-lint: https://github.com/edx/edx-lint +# This file was generated by edx-lint: https://github.com/openedx/edx-lint # # If you want to change this file, you have two choices, depending on whether # you want to make a local change that applies only to this repo, or whether @@ -28,7 +28,7 @@ # CENTRAL CHANGE: # # 1. Edit the pylintrc file in the edx-lint repo at -# https://github.com/edx/edx-lint/blob/master/edx_lint/files/pylintrc +# https://github.com/openedx/edx-lint/blob/master/edx_lint/files/pylintrc # # 2. install the updated version of edx-lint (in edx-lint): # @@ -64,12 +64,13 @@ # SERIOUSLY. # # ------------------------------ -# Generated by edx-lint version: 5.2.2 +# Generated by edx-lint version: 5.3.4 # ------------------------------ [MASTER] ignore = ,migrations, settings, wsgi.py persistent = yes load-plugins = edx_lint.pylint,pylint_django,pylint_celery +check-quote-consistency = true [MESSAGES CONTROL] enable = @@ -102,20 +103,12 @@ enable = cell-var-from-loop, confusing-with-statement, continue-in-finally, - cyclical-import, dangerous-default-value, - dict-items-not-iterating, - dict-keys-not-iterating, - dict-values-not-iterating, duplicate-argument-name, duplicate-bases, duplicate-except, duplicate-key, - eq-without-hash, - exception-escape, - exception-message-attribute, expression-not-assigned, - filter-builtin-not-iterating, format-combined-specification, format-needs-mapping, function-redefined, @@ -123,33 +116,26 @@ enable = import-error, import-self, inconsistent-mro, - indexing-exception, inherit-non-class, init-is-generator, invalid-all-object, - invalid-encoded-data, invalid-format-index, invalid-length-returned, invalid-sequence-index, invalid-slice-index, invalid-slots-object, invalid-slots, - invalid-str-codec, invalid-unary-operand-type, logging-too-few-args, logging-too-many-args, logging-unsupported-format, lost-exception, - map-builtin-not-iterating, method-hidden, misplaced-bare-raise, misplaced-future, missing-format-argument-key, missing-format-attribute, missing-format-string-key, - missing-super-argument, - mixed-fomat-string, - model-unicode-not-callable, no-member, no-method-argument, no-name-in-module, @@ -158,8 +144,6 @@ enable = non-iterator-returned, non-parent-method-called, nonexistent-operator, - nonimplemented-raised, - nonstandard-exception, not-a-mapping, not-an-iterable, not-callable, @@ -167,35 +151,25 @@ enable = not-in-loop, pointless-statement, pointless-string-statement, - property-on-old-class, raising-bad-type, raising-non-exception, - raising-string, - range-builtin-not-iterating, redefined-builtin, - redefined-in-handler, redefined-outer-name, - redefined-variable-type, redundant-keyword-arg, - relative-import, repeated-keyword, return-arg-in-generator, return-in-init, return-outside-function, signature-differs, - slots-on-old-class, super-init-not-called, super-method-not-called, - super-on-old-class, syntax-error, - sys-max-int, test-inherits-tests, too-few-format-args, too-many-format-args, too-many-function-args, translation-of-non-string, truncated-format-string, - unbalance-tuple-unpacking, undefined-all-variable, undefined-loop-variable, undefined-variable, @@ -211,11 +185,8 @@ enable = used-before-assignment, using-constant-test, yield-outside-function, - zip-builtin-not-iterating, astroid-error, - django-not-available-placeholder, - django-not-available, fatal, method-check-failed, parse-error, @@ -237,7 +208,6 @@ enable = bad-classmethod-argument, bad-mcs-classmethod-argument, bad-mcs-method-argument, - bad-whitespace, bare-except, broad-except, consider-iterating-dictionary, @@ -247,16 +217,10 @@ enable = literal-used-as-attribute, logging-format-interpolation, logging-not-lazy, - metaclass-assignment, - model-has-unicode, - model-missing-unicode, - model-no-explicit-unicode, multiple-imports, multiple-statements, no-classmethod-decorator, no-staticmethod-decorator, - old-raise-syntax, - old-style-class, protected-access, redundant-unittest-assert, reimported, @@ -284,7 +248,6 @@ enable = wrong-import-position, missing-final-newline, - mixed-indentation, mixed-line-endings, trailing-newlines, trailing-whitespace, @@ -295,26 +258,9 @@ enable = deprecated-pragma, unrecognized-inline-option, useless-suppression, - - cmp-method, - coerce-method, - delslice-method, - dict-iter-method, - dict-view-method, - div-method, - getslice-method, - hex-method, - idiv-method, - next-method-called, - next-method-defined, - nonzero-method, - oct-method, - rdiv-method, - setslice-method, - using-cmp-argument, disable = - bad-continuation, bad-indentation, + broad-exception-raised, consider-using-f-string, duplicate-code, file-ignored, @@ -322,12 +268,7 @@ disable = global-statement, invalid-name, locally-disabled, - locally-enabled, - lowercase-l-suffix, - misplaced-comparison-constant, no-else-return, - no-init, - no-self-use, suppressed-message, too-few-public-methods, too-many-ancestors, @@ -346,44 +287,6 @@ disable = feature-toggle-needs-doc, illegal-waffle-usage, - apply-builtin, - backtick, - bad-python3-import, - basestring-builtin, - buffer-builtin, - cmp-builtin, - coerce-builtin, - deprecated-itertools-function, - deprecated-operator-function, - deprecated-str-translate-call, - deprecated-string-function, - deprecated-sys-function, - deprecated-types-field, - deprecated-urllib-function, - execfile-builtin, - file-builtin, - import-star-module-level, - input-builtin, - intern-builtin, - long-builtin, - long-suffix, - no-absolute-import, - non-ascii-bytes-literal, - old-division, - old-ne-operator, - old-octal-literal, - parameter-unpacking, - print-statement, - raw_input-builtin, - reduce-builtin, - reload-builtin, - round-builtin, - standarderror-builtin, - unichr-builtin, - unicode-builtin, - unpacking-in-except, - xrange-builtin, - logging-fstring-interpolation, invalid-name, django-not-configured, @@ -391,12 +294,10 @@ disable = [REPORTS] output-format = text -files-output = no reports = no score = no [BASIC] -bad-functions = map,filter,apply,input module-rgx = (([a-z_][a-z0-9_]*)|([A-Z][a-zA-Z0-9]+))$ const-rgx = (([A-Z_][A-Z0-9_]*)|(__.*__)|log|urlpatterns|logger|User)$ class-rgx = [A-Z_][a-zA-Z0-9]+$ @@ -416,7 +317,6 @@ docstring-min-length = 5 max-line-length = 120 ignore-long-lines = ^\s*(# )?((?)|(\.\. \w+: .*))$ single-line-if-stmt = no -no-space-check = trailing-comma,dict-separator max-module-lines = 1000 indent-string = ' ' @@ -485,6 +385,6 @@ ext-import-graph = int-import-graph = [EXCEPTIONS] -overgeneral-exceptions = Exception +overgeneral-exceptions = builtins.Exception -# e6cc69b5996fe393e4e13ca4048f297f2a7ef519 +# fc49f9d7fe958e66c1b1da2ca9ef156bee09f068 diff --git a/pylintrc_tweaks b/pylintrc_tweaks index c4607e5c..c230f77b 100644 --- a/pylintrc_tweaks +++ b/pylintrc_tweaks @@ -1,5 +1,6 @@ [MASTER] ignore+= ,migrations, settings, wsgi.py +check-quote-consistency = true [BASIC] const-rgx = (([A-Z_][A-Z0-9_]*)|(__.*__)|log|urlpatterns|logger|User)$