diff --git a/.github/workflows/quality-checks.yml b/.github/workflows/quality-checks.yml index 6bf16c9f0b2f..d5c5483bd0d0 100644 --- a/.github/workflows/quality-checks.yml +++ b/.github/workflows/quality-checks.yml @@ -80,3 +80,12 @@ jobs: **/reports/**/* test_root/log/**/*.log *.log + + - name: Run ruff quality tests + id: run-ruff + run: | + ruff check lms/djangoapps/ lms/envs/ lms/lib/ lms/tests.py \ + openedx/core/djangoapps/ openedx/core/djangolib/ openedx/core/lib/ openedx/core/tests/ \ + openedx/core/tests/ openedx/core/types/ openedx/features/ openedx/testing/ openedx/tests/ \ + cms common xmodule --preview --verbose + diff --git a/Makefile b/Makefile index 6fc019290088..4df68aef89ba 100644 --- a/Makefile +++ b/Makefile @@ -207,3 +207,8 @@ migrate: migrate-lms migrate-cms # Part of https://github.com/openedx/wg-developer-experience/issues/136 ubuntu-requirements: ## Install ubuntu 22.04 system packages needed for `pip install` to work on ubuntu. sudo apt install libmysqlclient-dev libxmlsec1-dev +ruff: ## Run ruff + ruff check lms/djangoapps/ lms/envs/ lms/lib/ lms/tests.py \ + openedx/core/djangoapps/ openedx/core/djangolib/ openedx/core/lib/ openedx/core/tests/ \ + openedx/core/tests/ openedx/core/types/ openedx/features/ openedx/testing/ openedx/tests/ \ + cms common xmodule --preview diff --git a/common/djangoapps/student/models/course_enrollment.py b/common/djangoapps/student/models/course_enrollment.py index 318a3afd8316..e7fc27c0d461 100644 --- a/common/djangoapps/student/models/course_enrollment.py +++ b/common/djangoapps/student/models/course_enrollment.py @@ -1681,7 +1681,7 @@ def refund_window(self, refund_window): class BulkUnenrollConfiguration(ConfigurationModel): # lint-amnesty, pylint: disable=empty-docstring """ - + config model for the bulk_unenroll_csv command """ csv_file = models.FileField( validators=[FileExtensionValidator(allowed_extensions=['csv'])], diff --git a/lms/djangoapps/courseware/views/views.py b/lms/djangoapps/courseware/views/views.py index 3bf8ae10e8c2..30cc45a67c50 100644 --- a/lms/djangoapps/courseware/views/views.py +++ b/lms/djangoapps/courseware/views/views.py @@ -601,9 +601,9 @@ def handle_exceptions(request, course_key, course, exception): Handle exceptions raised when rendering a view. """ if isinstance(exception, Redirect) or isinstance(exception, Http404): # lint-amnesty, pylint: disable=consider-merging-isinstance - raise # lint-amnesty, pylint: disable=misplaced-bare-raise + raise # lint-amnesty, pylint: disable=misplaced-bare-raise # noqa: PLE0704 if settings.DEBUG: - raise # lint-amnesty, pylint: disable=misplaced-bare-raise + raise # lint-amnesty, pylint: disable=misplaced-bare-raise # noqa: PLE0704 user = request.user log.exception( "Error in %s: user=%s, effective_user=%s, course=%s", diff --git a/openedx/core/lib/api/view_utils.py b/openedx/core/lib/api/view_utils.py index 054755ae3cc1..55426aefc6c5 100644 --- a/openedx/core/lib/api/view_utils.py +++ b/openedx/core/lib/api/view_utils.py @@ -97,7 +97,7 @@ def handle_exception(self, exc): elif isinstance(exc, ValidationError): return self._make_validation_error_response(exc) else: - raise # lint-amnesty, pylint: disable=misplaced-bare-raise + raise # lint-amnesty, pylint: disable=misplaced-bare-raise # noqa: PLE0704 class ExpandableFieldViewMixin: diff --git a/requirements/edx/development.txt b/requirements/edx/development.txt index 11ad4f85cd8a..aa0a128d4ae8 100644 --- a/requirements/edx/development.txt +++ b/requirements/edx/development.txt @@ -2296,7 +2296,8 @@ zipp==3.18.1 # -r requirements/edx/testing.txt # importlib-metadata # importlib-resources - +ruff==0.1.3 + # via -r requirements/edx/testing.in # The following packages are considered to be unsafe in a requirements file: # pip # setuptools diff --git a/requirements/edx/testing.in b/requirements/edx/testing.in index b903768f4de6..0a62c04526b4 100644 --- a/requirements/edx/testing.in +++ b/requirements/edx/testing.in @@ -39,6 +39,7 @@ pytest-json-report # Output json formatted warnings after running pytest pytest-metadata==1.8.0 # To prevent 'make upgrade' failure, dependency of pytest-json-report pytest-randomly # pytest plugin to randomly order tests pytest-xdist[psutil] # Parallel execution of tests on multiple CPU cores or hosts +ruff # rust based linter singledispatch # Backport of functools.singledispatch from Python 3.4+, used in tests of XBlock rendering testfixtures # Provides a LogCapture utility used by several tests tox # virtualenv management for tests diff --git a/requirements/edx/testing.txt b/requirements/edx/testing.txt index e8df4b1a0eb7..44e0c3300adb 100644 --- a/requirements/edx/testing.txt +++ b/requirements/edx/testing.txt @@ -1676,6 +1676,7 @@ zipp==3.18.1 # -r requirements/edx/base.txt # importlib-metadata # importlib-resources - +ruff==0.1.3 + # via -r requirements/edx/testing.in # The following packages are considered to be unsafe in a requirements file: # setuptools diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000000..f21610f1b74c --- /dev/null +++ b/ruff.toml @@ -0,0 +1,135 @@ +select = [ + "A001", # redefined-builtin + "ARG001", # unused-argument + "B002", # nonexistent-operator + "B006", # dangerous-default-value + "B012", # lost-exception + "B014", # duplicate-except + "B018", # expression-not-assigned + "B018", # pointless-statement + "B023", # cell-var-from-loop + "D419", # empty-docstring + "E401", # multiple-imports + "E501", # line-too-long + "E702", # multiple-statements + "E703", # unnecessary-semicolon + "E712", # singleton-comparison + "E721", # unidiomatic-typecheck + "E722", # bare-except + "E999", # syntax-error + "F401", # unused-import + "F403", # wildcard-import + "F404", # misplaced-future + "F501", # truncated-format-string + "F502", # format-needs-mapping + "F504", # unused-format-string-key + "F507", # unused-format-string-argument + "F522", # too-many-format-args + "F524", # missing-format-argument-key + "F524", # missing-format-string-key + "F524", # too-few-format-args + "F525", # format-combined-specification + "F601", # duplicate-key + "F631", # assert-on-tuple + "F702", # not-in-loop + "F704", # yield-outside-function + "F706", # return-outside-function + "F811", # function-redefined + "F811", # reimported + "F821", # undefined-variable + "F822", # undefined-all-variable + "F841", # unused-variable + "FIX004", # fixme + "G", # logging-format-interpolation + "G", # logging-fstring-interpolation + "G", # logging-not-lazy + "I001", # ungrouped-imports + "I001", # wrong-import-order + "N804", # bad-classmethod-argument + "N805", # no-method-argument + "N805", # no-self-argument + "N815", # invalid-name + "PGH001", # eval-used + "PIE790", # unnecessary-pass + "PLE0101", # return-in-init + "PLE0116", # continue-in-finally + "PLE0241", # duplicate-bases + "PLE0302", # unexpected-special-method-signature + "PLE0604", # invalid-all-object + "PLE0704", # misplaced-bare-raise + "PLE1205", # logging-too-many-args + "PLE1206", # logging-too-few-args + "PLE1310", # bad-str-strip-call + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLR0915", # too-many-statements + "PLR0916", # too-many-boolean-expressions + "PLW0120", # useless-else-on-loop + "PLW0406", # import-self + "PLW0602", # global-variable-not-assigned + "PLW0603", # global-statement + "PLW0711", # binary-op-exception + "PLW1514", # unspecified-encoding + "RET502", # inconsistent-return-statements + "RET505", # no-else-return + "RET507", # no-else-continue + "RET508", # no-else-break + "S102", # exec-used + "SIM118", # consider-iterating-dictionary + "SIM208", # unneeded-not + "UP004", # useless-object-inheritance + "W292", # missing-final-newline + "W605", # anomalous-backslash-in-string +] + +ignore = [ + "ARG001", # unused-argument + "F841", # unused-variable + "FIX004", # fixme + "G", # logging-format-interpolation + "G", # logging-fstring-interpolation + "I001", # ungrouped-imports + "I001", # wrong-import-order + "N815", # invalid-name + "PLR0904", # too-many-public-methods + "PLR0911", # too-many-return-statements + "PLR0912", # too-many-branches + "PLR0913", # too-many-arguments + "PLW0603", # global-statement + "PLW1514", # unspecified-encoding + "RET502", # inconsistent-return-statements + "RET505", # no-else-return + "RET507", # no-else-continue + "RET508", # no-else-break + "UP004", # useless-object-inheritance + + # enabled in pylint but failing in ruff because of too many inline suppressions + "A001", # redefined-builtin + "B006", # dangerous-default-value + "B018", # expression-not-assigned + "B018", # pointless-statement + "B023", # cell-var-from-loop + "E501", # line-too-long + "E712", # singleton-comparison + "E721", # unidiomatic-typecheck + "E722", # bare-except + "F403", # wildcard-import + "F811", # function-redefined + "F811", # reimported + "F821", # undefined-variable + "N804", # bad-classmethod-argument + "N805", # no-method-argument + "N805", # no-self-argument + "PGH001", # eval-used + "PIE790", # unnecessary-pass + "PLR0915", # too-many-statements + "PLW0602", # global-variable-not-assigned + "SIM118", # consider-iterating-dictionary + "F401", # unused-import +] + +[lint.extend-per-file-ignores] +# Also ignore `E402` in all `__init__.py` files. +"__init__.py" = ["E402"] diff --git a/scripts/generic-ci-tests.sh b/scripts/generic-ci-tests.sh index 54b9cbb9d500..7ae28b70d379 100755 --- a/scripts/generic-ci-tests.sh +++ b/scripts/generic-ci-tests.sh @@ -76,7 +76,6 @@ case "$TEST_SUITE" in EXIT=0 mkdir -p reports - echo "Finding pycodestyle violations and storing report..." run_paver_quality run_pep8 || { EXIT=1; } echo "Finding ESLint violations and storing report..." diff --git a/xmodule/capa/responsetypes.py b/xmodule/capa/responsetypes.py index 73378e7c0a2b..214abe86fd16 100644 --- a/xmodule/capa/responsetypes.py +++ b/xmodule/capa/responsetypes.py @@ -3900,7 +3900,7 @@ def _check_student_inputs(self, numtolerance_inputs): # FIXME: To be replaced by auto-registration # pylint: disable=invalid-all-object -__all__ = [ +__all__ = [ # noqa: PLE0604 CodeResponse, NumericalResponse, FormulaResponse, diff --git a/xmodule/modulestore/__init__.py b/xmodule/modulestore/__init__.py index f3aee2a58f24..c4fb71fdf4da 100644 --- a/xmodule/modulestore/__init__.py +++ b/xmodule/modulestore/__init__.py @@ -221,7 +221,7 @@ def _get_bulk_ops_record(self, course_key, ignore_case=False): # Shortcut: check basic equivalence for cases where org/course/run might be None. key_library = get_library_or_course_attribute(key) course_library = get_library_or_course_attribute(course_key) - if (key == course_key) or ( # lint-amnesty, pylint: disable=too-many-boolean-expressions + if (key == course_key) or ( # lint-amnesty, pylint: disable=too-many-boolean-expressions # noqa: PLR0916 (key.org and key.org.lower() == course_key.org.lower()) and (key_library and key_library.lower() == course_library.lower()) and (key.run and key.run.lower() == course_key.run.lower())