diff --git a/cms/djangoapps/contentstore/management/commands/backfill_course_tabs.py b/cms/djangoapps/contentstore/management/commands/backfill_course_tabs.py index 878a8dabaa27..e2a44d8a9fff 100644 --- a/cms/djangoapps/contentstore/management/commands/backfill_course_tabs.py +++ b/cms/djangoapps/contentstore/management/commands/backfill_course_tabs.py @@ -71,6 +71,5 @@ def handle(self, *args, **options): if error_keys: msg = 'The following courses encountered errors and were not updated:\n' - for error_key in error_keys: - msg += f' - {error_key}\n' + msg += ''.join([f' - {error_key}\n' for error_key in error_keys]) logger.info(msg) diff --git a/cms/djangoapps/contentstore/management/commands/export_content_library.py b/cms/djangoapps/contentstore/management/commands/export_content_library.py index 0b4cbfb1fbad..b56c172e374e 100644 --- a/cms/djangoapps/contentstore/management/commands/export_content_library.py +++ b/cms/djangoapps/contentstore/management/commands/export_content_library.py @@ -51,16 +51,15 @@ def handle(self, *args, **options): tarball = tasks.create_export_tarball(library, library_key, {}, None) except Exception as e: raise CommandError(f'Failed to export "{library_key}" with "{e}"') # lint-amnesty, pylint: disable=raise-missing-from - else: - with tarball: - # Save generated archive with keyed filename - prefix, suffix, n = str(library_key).replace(':', '+'), '.tar.gz', 0 - while os.path.exists(prefix + suffix): - n += 1 - prefix = '{}_{}'.format(prefix.rsplit('_', 1)[0], n) if n > 1 else f'{prefix}_1' - filename = prefix + suffix - target = os.path.join(dest_path, filename) - tarball.file.seek(0) - with open(target, 'wb') as f: - shutil.copyfileobj(tarball.file, f) - print(f'Library "{library.location.library_key}" exported to "{target}"') + with tarball: + # Save generated archive with keyed filename + prefix, suffix, n = str(library_key).replace(':', '+'), '.tar.gz', 0 + while os.path.exists(prefix + suffix): + n += 1 + prefix = '{}_{}'.format(prefix.rsplit('_', 1)[0], n) if n > 1 else f'{prefix}_1' + filename = prefix + suffix + target = os.path.join(dest_path, filename) + tarball.file.seek(0) + with open(target, 'wb') as f: + shutil.copyfileobj(tarball.file, f) + print(f'Library "{library.location.library_key}" exported to "{target}"') diff --git a/common/djangoapps/student/management/commands/bulk_change_enrollment_csv.py b/common/djangoapps/student/management/commands/bulk_change_enrollment_csv.py index a9c1d5349858..a938d2d50372 100644 --- a/common/djangoapps/student/management/commands/bulk_change_enrollment_csv.py +++ b/common/djangoapps/student/management/commands/bulk_change_enrollment_csv.py @@ -81,7 +81,7 @@ def handle(self, *args, **options): self.change_enrollments(csv_file) else: - CommandError('No file is provided. File is required') + CommandError('No file is provided. File is required') # pylint: disable=pointless-exception-statement def change_enrollments(self, csv_file): """ change the enrollments of the learners. """ diff --git a/common/djangoapps/student/models/user.py b/common/djangoapps/student/models/user.py index aa3de546ef2b..69d019f637c1 100644 --- a/common/djangoapps/student/models/user.py +++ b/common/djangoapps/student/models/user.py @@ -1020,7 +1020,7 @@ def check_user_reset_password_threshold(cls, user): return record.failure_count >= max_failures_allowed / 2, record.failure_count @classmethod - def clear_lockout_counter(cls, user): + def clear_lockout_counter(cls, user): # pylint: disable=useless-return """ Removes the lockout counters (normally called after a successful login) """ diff --git a/common/djangoapps/track/views/segmentio.py b/common/djangoapps/track/views/segmentio.py index 2ab5306232c5..8a35a0e421cf 100644 --- a/common/djangoapps/track/views/segmentio.py +++ b/common/djangoapps/track/views/segmentio.py @@ -205,9 +205,8 @@ def track_segmentio_event(request): # pylint: disable=too-many-statements raise EventValidationError(ERROR_USER_NOT_EXIST) # lint-amnesty, pylint: disable=raise-missing-from except ValueError: raise EventValidationError(ERROR_INVALID_USER_ID) # lint-amnesty, pylint: disable=raise-missing-from - else: - context['user_id'] = user.id - context['username'] = user.username + context['user_id'] = user.id + context['username'] = user.username # course_id is expected to be provided in the context when applicable course_id = context.get('course_id') diff --git a/lms/djangoapps/discussion/rest_api/api.py b/lms/djangoapps/discussion/rest_api/api.py index 19ccf26d19a4..0f23404ca2d2 100644 --- a/lms/djangoapps/discussion/rest_api/api.py +++ b/lms/djangoapps/discussion/rest_api/api.py @@ -1010,7 +1010,7 @@ def get_thread_list( if view in ["unread", "unanswered", "unresponded"]: query_params[view] = "true" else: - ValidationError({ + ValidationError({ # pylint: disable=pointless-exception-statement "view": [f"Invalid value. '{view}' must be 'unread' or 'unanswered'"] }) diff --git a/lms/djangoapps/discussion/tasks.py b/lms/djangoapps/discussion/tasks.py index 3fef4f5f7cef..d483388f54ae 100644 --- a/lms/djangoapps/discussion/tasks.py +++ b/lms/djangoapps/discussion/tasks.py @@ -120,8 +120,6 @@ def send_ace_message(context): # lint-amnesty, pylint: disable=missing-function log.info('Sending forum comment notification with context %s', message_context) ace.send(message, limit_to_channels=[ChannelType.PUSH]) _track_notification_sent(message, context) - else: - return @shared_task(base=LoggedTask) diff --git a/lms/djangoapps/experiments/flags.py b/lms/djangoapps/experiments/flags.py index b83a7751fae7..3b45bcee5b5c 100644 --- a/lms/djangoapps/experiments/flags.py +++ b/lms/djangoapps/experiments/flags.py @@ -245,7 +245,7 @@ def get_bucket(self, course_key=None, track=True): if ( track and hasattr(request, 'session') and session_key not in request.session and - not masquerading_as_specific_student and not anonymous + not masquerading_as_specific_student and not anonymous # pylint: disable=used-before-assignment ): segment.track( user_id=user.id, diff --git a/lms/djangoapps/static_template_view/views.py b/lms/djangoapps/static_template_view/views.py index a788f77a95fd..f8962897c033 100644 --- a/lms/djangoapps/static_template_view/views.py +++ b/lms/djangoapps/static_template_view/views.py @@ -92,8 +92,7 @@ def render_press_release(request, slug): resp = render_to_response('static_templates/press_releases/' + template, {}) except TemplateDoesNotExist: raise Http404 # lint-amnesty, pylint: disable=raise-missing-from - else: - return resp + return resp @fix_crum_request diff --git a/lms/envs/test.py b/lms/envs/test.py index a9e8aaf9f2e2..632f5c1d703e 100644 --- a/lms/envs/test.py +++ b/lms/envs/test.py @@ -412,7 +412,11 @@ FACEBOOK_API_VERSION = "v2.8" ######### custom courses ######### -INSTALLED_APPS += ['lms.djangoapps.ccx', 'openedx.core.djangoapps.ccxcon.apps.CCXConnectorConfig'] +INSTALLED_APPS += [ + 'lms.djangoapps.ccx', + 'openedx.core.djangoapps.ccxcon.apps.CCXConnectorConfig', + 'openedx.core.djangoapps.content_staging', +] FEATURES['CUSTOM_COURSES_EDX'] = True # Set dummy values for profile image settings. diff --git a/openedx/core/djangoapps/credit/models.py b/openedx/core/djangoapps/credit/models.py index 2a9fa2088551..9c14a15104b9 100644 --- a/openedx/core/djangoapps/credit/models.py +++ b/openedx/core/djangoapps/credit/models.py @@ -514,7 +514,6 @@ def remove_requirement_status(cls, username, requirement): ) ) log.error(log_msg) - return @classmethod def retire_user(cls, retirement): diff --git a/openedx/core/djangoapps/credit/tasks.py b/openedx/core/djangoapps/credit/tasks.py index 312e278a985f..79ef613e3d19 100644 --- a/openedx/core/djangoapps/credit/tasks.py +++ b/openedx/core/djangoapps/credit/tasks.py @@ -41,8 +41,7 @@ def update_credit_course_requirements(course_id): except (InvalidKeyError, ItemNotFoundError, InvalidCreditRequirements) as exc: LOGGER.error('Error on adding the requirements for course %s - %s', course_id, str(exc)) raise update_credit_course_requirements.retry(args=[course_id], exc=exc) - else: - LOGGER.info('Requirements added for course %s', course_id) + LOGGER.info('Requirements added for course %s', course_id) def _get_course_credit_requirements(course_key): diff --git a/openedx/core/djangoapps/enrollments/data.py b/openedx/core/djangoapps/enrollments/data.py index 9986830a3491..b76042f72c9d 100644 --- a/openedx/core/djangoapps/enrollments/data.py +++ b/openedx/core/djangoapps/enrollments/data.py @@ -341,8 +341,7 @@ def get_course_enrollment_info(course_id, include_expired=False): msg = f"Requested enrollment information for unknown course {course_id}" log.warning(msg) raise CourseNotFoundError(msg) # lint-amnesty, pylint: disable=raise-missing-from - else: - return CourseSerializer(course, include_expired=include_expired).data + return CourseSerializer(course, include_expired=include_expired).data def get_user_roles(username): diff --git a/openedx/core/djangoapps/safe_sessions/middleware.py b/openedx/core/djangoapps/safe_sessions/middleware.py index f3948217efd9..950a3e08c54f 100644 --- a/openedx/core/djangoapps/safe_sessions/middleware.py +++ b/openedx/core/djangoapps/safe_sessions/middleware.py @@ -244,14 +244,13 @@ def parse(cls, safe_cookie_string): raise SafeCookieError( # lint-amnesty, pylint: disable=raise-missing-from f"SafeCookieData BWC parse error: {safe_cookie_string!r}." ) - else: - if safe_cookie_data.version != cls.CURRENT_VERSION: - raise SafeCookieError( - "SafeCookieData version {!r} is not supported. Current version is {}.".format( - safe_cookie_data.version, - cls.CURRENT_VERSION, - )) - return safe_cookie_data + if safe_cookie_data.version != cls.CURRENT_VERSION: + raise SafeCookieError( + "SafeCookieData version {!r} is not supported. Current version is {}.".format( + safe_cookie_data.version, + cls.CURRENT_VERSION, + )) + return safe_cookie_data def __str__(self): """ diff --git a/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py b/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py index e465ff5610ed..d194e58ee880 100644 --- a/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py +++ b/openedx/core/djangoapps/user_api/management/commands/bulk_user_org_email_optout.py @@ -135,11 +135,10 @@ def handle(self, *args, **options): optout_rows[end_idx][0], optout_rows[end_idx][1], str(err)) raise - else: - cursor.execute('COMMIT;') - log.info("Committed opt-out for rows (%s, %s) through (%s, %s).", - optout_rows[start_idx][0], optout_rows[start_idx][1], - optout_rows[end_idx][0], optout_rows[end_idx][1]) + cursor.execute('COMMIT;') + log.info("Committed opt-out for rows (%s, %s) through (%s, %s).", + optout_rows[start_idx][0], optout_rows[start_idx][1], + optout_rows[end_idx][0], optout_rows[end_idx][1]) log.info("Sleeping %s seconds...", sleep_between) time.sleep(sleep_between) curr_row_idx += chunk_size diff --git a/openedx/core/lib/api/view_utils.py b/openedx/core/lib/api/view_utils.py index 054755ae3cc1..d876e49ae579 100644 --- a/openedx/core/lib/api/view_utils.py +++ b/openedx/core/lib/api/view_utils.py @@ -265,8 +265,7 @@ def __len__(self): def __iter__(self): # Yield all the known data first - for item in self._data: - yield item + yield from self._data # Capture and yield data from the underlying iterator # until it is exhausted diff --git a/openedx/core/lib/celery/task_utils.py b/openedx/core/lib/celery/task_utils.py index 738f074be68c..9a54f1b3a550 100644 --- a/openedx/core/lib/celery/task_utils.py +++ b/openedx/core/lib/celery/task_utils.py @@ -50,9 +50,8 @@ def emulate_http_request(site=None, user=None, middleware_classes=None): for middleware in reversed(middleware_instances): _run_method_if_implemented(middleware, 'process_exception', request, exc) raise - else: - for middleware in reversed(middleware_instances): - _run_method_if_implemented(middleware, 'process_response', request, response) + for middleware in reversed(middleware_instances): + _run_method_if_implemented(middleware, 'process_response', request, response) def _run_method_if_implemented(instance, method_name, *args, **kwargs): diff --git a/pavelib/paver_tests/utils.py b/pavelib/paver_tests/utils.py index 1db26cf76a4c..b2278c0d4d8b 100644 --- a/pavelib/paver_tests/utils.py +++ b/pavelib/paver_tests/utils.py @@ -93,5 +93,3 @@ def unexpected_fail_on_npm_install(*args, **kwargs): # pylint: disable=unused-a """ if ["npm", "install", "--verbose"] == args[0]: # lint-amnesty, pylint: disable=no-else-raise raise BuildFailure('Subprocess return code: 50') - else: - return diff --git a/pylint_django_settings.py b/pylint_django_settings.py index 46abfd81f883..31120c69efa9 100644 --- a/pylint_django_settings.py +++ b/pylint_django_settings.py @@ -1,5 +1,4 @@ -from pylint_django.checkers import ForeignKeyStringsChecker -from pylint_plugin_utils import get_checker +import sys class ArgumentCompatibilityError(Exception): @@ -47,6 +46,5 @@ def load_configuration(linter): """ Configures the Django settings module based on the command-line arguments passed to pylint. """ - name_checker = get_checker(linter, ForeignKeyStringsChecker) - arguments = linter.cmdline_parser.parse_args()[1] - name_checker.config.django_settings_module = _get_django_settings_module(arguments) + arguments = sys.argv[1:] + linter.config.django_settings_module = _get_django_settings_module(arguments) diff --git a/pylintrc b/pylintrc index 55a9bbab3b9c..492fbebeea94 100644 --- a/pylintrc +++ b/pylintrc @@ -64,7 +64,7 @@ # SERIOUSLY. # # ------------------------------ -# Generated by edx-lint version: 5.3.7 +# Generated by edx-lint version: 5.4.0 # ------------------------------ [MASTER] ignore = ,.git,.tox,migrations,node_modules,.pycharm_helpers @@ -314,6 +314,10 @@ disable = c-extension-no-member, no-name-in-module, unnecessary-lambda-assignment, + too-many-positional-arguments, + use-dict-literal, + possibly-used-before-assignment, + superfluous-parens, [REPORTS] output-format = text @@ -410,4 +414,4 @@ int-import-graph = [EXCEPTIONS] overgeneral-exceptions = builtins.Exception -# e624ea03d8124aa9cf2e577f830632344a0a07d9 +# bc7021ad247d80c14dda494aae1f3ebb63758910 diff --git a/pylintrc_tweaks b/pylintrc_tweaks index 1633da5c10a4..46823f44ee4b 100644 --- a/pylintrc_tweaks +++ b/pylintrc_tweaks @@ -33,6 +33,10 @@ disable+ = c-extension-no-member, no-name-in-module, unnecessary-lambda-assignment, + too-many-positional-arguments, + use-dict-literal, + possibly-used-before-assignment, + superfluous-parens [BASIC] attr-rgx = [a-z_][a-z0-9_]{2,40}$ diff --git a/requirements/constraints.txt b/requirements/constraints.txt index 4bf073dfab05..efb3c6419c4d 100644 --- a/requirements/constraints.txt +++ b/requirements/constraints.txt @@ -164,10 +164,6 @@ path<16.12.0 # Constraint can be removed once the issue https://github.com/PyCQA/pycodestyle/issues/1090 is fixed. pycodestyle<2.9.0 -# Date: 2021-07-12 -# Issue for unpinning: https://github.com/openedx/edx-platform/issues/33560 -pylint<2.16.0 # greater version failing quality test. Fix them in seperate ticket. - # Date: 2021-08-25 # At the time of writing this comment, we do not know whether py2neo>=2022 # will support our currently-deployed Neo4j version (3.5). diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 2bda2d2adf86..546e660f2279 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -81,7 +81,7 @@ asn1crypto==1.5.1 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # snowflake-connector-python -astroid==2.13.5 +astroid==3.3.5 # via # -r requirements/edx/testing.txt # pylint @@ -1164,10 +1164,6 @@ lazy==1.6 # lti-consumer-xblock # ora2 # xblock -lazy-object-proxy==1.10.0 - # via - # -r requirements/edx/testing.txt - # astroid libsass==0.10.0 # via # -c requirements/edx/../constraints.txt @@ -1604,9 +1600,8 @@ pylatexenc==2.10 # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt # olxcleaner -pylint==2.15.10 +pylint==3.3.1 # via - # -c requirements/edx/../constraints.txt # -r requirements/edx/testing.txt # edx-lint # pylint-celery @@ -1617,7 +1612,7 @@ pylint-celery==0.3 # via # -r requirements/edx/testing.txt # edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via # -r requirements/edx/testing.txt # edx-lint @@ -1626,7 +1621,7 @@ pylint-plugin-utils==0.8.2 # -r requirements/edx/testing.txt # pylint-celery # pylint-django -pylint-pytest==0.3.0 +pylint-pytest==1.1.7 # via -r requirements/edx/testing.txt pylti1p3==2.0.0 # via @@ -2235,7 +2230,6 @@ wrapt==1.16.0 # via # -r requirements/edx/doc.txt # -r requirements/edx/testing.txt - # astroid xblock[django]==5.1.0 # via # -r requirements/edx/doc.txt diff --git a/requirements/edx/testing.in b/requirements/edx/testing.in index b903768f4de6..64ddaa047ca7 100644 --- a/requirements/edx/testing.in +++ b/requirements/edx/testing.in @@ -43,6 +43,6 @@ singledispatch # Backport of functools.singledispatch from Python 3.4 testfixtures # Provides a LogCapture utility used by several tests tox # virtualenv management for tests unidiff # Required by coverage_pytest_plugin -pylint-pytest==0.3.0 # A Pylint plugin to suppress pytest-related false positives. +pylint-pytest==1.1.7 # A Pylint plugin to suppress pytest-related false positives. pact-python # Library for contract testing py # Needed for pytest configurations, was previously been fetched through tox diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index 217b9e637350..b32c878629cc 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -55,7 +55,7 @@ asn1crypto==1.5.1 # via # -r requirements/edx/base.txt # snowflake-connector-python -astroid==2.13.5 +astroid==3.3.5 # via # pylint # pylint-celery @@ -887,8 +887,6 @@ lazy==1.6 # lti-consumer-xblock # ora2 # xblock -lazy-object-proxy==1.10.0 - # via astroid libsass==0.10.0 # via # -c requirements/edx/../constraints.txt @@ -1212,9 +1210,8 @@ pylatexenc==2.10 # via # -r requirements/edx/base.txt # olxcleaner -pylint==2.15.10 +pylint==3.3.1 # via - # -c requirements/edx/../constraints.txt # edx-lint # pylint-celery # pylint-django @@ -1222,13 +1219,13 @@ pylint==2.15.10 # pylint-pytest pylint-celery==0.3 # via edx-lint -pylint-django==2.5.5 +pylint-django==2.6.1 # via edx-lint pylint-plugin-utils==0.8.2 # via # pylint-celery # pylint-django -pylint-pytest==0.3.0 +pylint-pytest==1.1.7 # via -r requirements/edx/testing.in pylti1p3==2.0.0 # via -r requirements/edx/base.txt @@ -1649,9 +1646,7 @@ webob==1.8.9 # -r requirements/edx/base.txt # xblock wrapt==1.16.0 - # via - # -r requirements/edx/base.txt - # astroid + # via -r requirements/edx/base.txt xblock[django]==5.1.0 # via # -r requirements/edx/base.txt diff --git a/xmodule/capa/tests/test_input_templates.py b/xmodule/capa/tests/test_input_templates.py index 4b14bd5ef86c..3048f62095de 100644 --- a/xmodule/capa/tests/test_input_templates.py +++ b/xmodule/capa/tests/test_input_templates.py @@ -76,8 +76,7 @@ def render_to_xml(self, context_dict): except Exception as exc: raise TemplateError("Could not parse XML from '{0}': {1}".format( # lint-amnesty, pylint: disable=raise-missing-from xml_str, str(exc))) - else: - return xml + return xml def assert_has_xpath(self, xml_root, xpath, context_dict, exact_num=1): """ diff --git a/xmodule/split_test_block.py b/xmodule/split_test_block.py index 05ca3a5db454..52f40547879a 100644 --- a/xmodule/split_test_block.py +++ b/xmodule/split_test_block.py @@ -419,9 +419,8 @@ def log_child_render(self, request, suffix=''): # lint-amnesty, pylint: disable ) ) raise - else: - self.runtime.publish(self, 'xblock.split_test.child_render', {'child_id': child_id}) - return Response() + self.runtime.publish(self, 'xblock.split_test.child_render', {'child_id': child_id}) + return Response() def get_icon_class(self): return self.child.get_icon_class() if self.child else 'other'