diff --git a/.flake8 b/.flake8 new file mode 100644 index 000000000000..a27dfabab003 --- /dev/null +++ b/.flake8 @@ -0,0 +1,130 @@ +[flake8] +max-line-length = 99 +exclude = + # These paths should be triaged and either fixed or moved to the list below. + devtools/shared, + dom/bindings/Codegen.py, + dom/bindings/parser/WebIDL.py, + dom/bindings/parser/tests/test_arraybuffer.py, + dom/bindings/parser/tests/test_securecontext_extended_attribute.py, + gfx/tests, + ipc/ipdl/ipdl, + layout/base/tests/marionette, + layout/reftests/border-image, + layout/reftests/fonts, + layout/reftests/w3c-css, + layout/style, + media/libdav1d/generate_source.py, + moz.configure, + netwerk/dns/prepare_tlds.py, + netwerk/protocol/http/make_incoming_tables.py, + python/l10n/fluent_migrations, + security/manager/ssl/tests/unit, + servo/components/style, + testing/condprofile/condprof/android.py, + testing/condprofile/condprof/creator.py, + testing/condprofile/condprof/desktop.py, + testing/condprofile/condprof/runner.py, + testing/condprofile/condprof/scenarii/heavy.py, + testing/condprofile/condprof/scenarii/settled.py, + testing/condprofile/condprof/scenarii/synced.py + testing/condprofile/condprof/helpers.py, + testing/jsshell/benchmark.py, + testing/marionette/mach_commands.py, + testing/mozharness/docs, + testing/mozharness/examples, + testing/mozharness/external_tools, + testing/mozharness/mach_commands.py, + testing/mozharness/manifestparser, + testing/mozharness/mozprocess, + testing/mozharness/setup.py, + testing/parse_build_tests_ccov.py, + testing/runtimes/writeruntimes.py, + testing/tools/iceserver/iceserver.py, + testing/tools/websocketprocessbridge/websocketprocessbridge.py, + toolkit/components/featuregates, + toolkit/content/tests/chrome/file_about_networking_wsh.py, + toolkit/library/build/dependentlibs.py, + toolkit/locales/generate_update_locale.py, + toolkit/mozapps, + toolkit/moz.configure, + toolkit/nss.configure, + + # mako files are not really python files + *.mako.py, + + # These paths are intentionally excluded (not necessarily for good reason). + build/moz.configure/*.configure, + build/pymake/, + browser/extensions/mortar/ppapi/, + browser/moz.configure, + dom/canvas/test/webgl-conf/checkout/closure-library/, + editor/libeditor/tests/browserscope/, + intl/icu/, + ipc/chromium/src/third_party/, + js/*.configure, + gfx/angle/, + gfx/harfbuzz, + gfx/skia/, + memory/moz.configure, + mobile/android/*.configure, + node_modules, + python/mozbuild/mozbuild/test/configure/data, + security/nss/, + testing/marionette/harness/marionette_harness/runner/mixins, + testing/marionette/harness/marionette_harness/tests, + testing/mochitest/pywebsocket3, + testing/mozharness/configs/test/test_malformed.py, + testing/web-platform/tests, + tools/lint/test/files, + tools/crashreporter/*.configure, + .ycm_extra_conf.py, + +# See: +# - http://flake8.pycqa.org/en/latest/user/error-codes.html +# - http://pep8.readthedocs.io/en/latest/intro.html#configuration +ignore = + # These should be triaged and either fixed or moved to the list below. + W605, W606, + # These are intentionally disabled (not necessarily for good reason). + # F723: syntax error in type comment + # text contains quotes which breaks our custom JSON formatter + F723, E704, E741, + + # black is already in charge of formatting, no need to start a formatter + # battle here + E1, W1, E2, W2, E3, W3, E4, W4, E5, W5 + +per-file-ignores = + # These paths are intentionally excluded. + ipc/ipdl/*: F403, F405 + layout/tools/reftest/selftest/conftest.py: F811 + # cpp_eclipse has a lot of multi-line embedded XML which exceeds line length + python/mozbuild/mozbuild/backend/cpp_eclipse.py: E501 + testing/firefox-ui/**/__init__.py: F401 + testing/marionette/**/__init__.py: F401 + testing/mochitest/tests/python/conftest.py: F811 + testing/mozbase/manifestparser/tests/test_filters.py: E731 + testing/mozbase/mozlog/tests/test_formatters.py: E501 + testing/mozharness/configs/*: E124, E127, E128, E131, E231, E261, E265, E266, E501, W391 + + # These paths contain Python-2 only syntax which cause errors since flake8 + # is run with Python 3. + build/compare-mozconfig/compare-mozconfigs.py: F821 + build/midl.py: F821 + build/pgo/genpgocert.py: F821 + config/MozZipFile.py: F821 + config/check_source_count.py: F821 + config/tests/unitMozZipFile.py: F821 + ipc/pull-chromium.py: F633 + js/src/**: F633, F821 + python/mozbuild/mozbuild/action/dump_env.py: F821 + python/mozbuild/mozbuild/dotproperties.py: F821 + python/mozbuild/mozbuild/testing.py: F821 + python/mozbuild/mozbuild/util.py: F821 + testing/mozharness/mozharness/mozilla/testing/android.py: F821 + testing/mochitest/runtests.py: F821 + +builtins = + # For GDB extensions + gdb diff --git a/.hgignore b/.hgignore index 21559a945dfd..f3b1e406eb54 100644 --- a/.hgignore +++ b/.hgignore @@ -225,9 +225,6 @@ _OPT\.OBJ/ # Unit test \.pytest_cache/ -# Ruff -\.ruff_cache/ - # Ignore files created when running a reftest. ^lextab.py$ diff --git a/.isort.cfg b/.isort.cfg new file mode 100644 index 000000000000..bf7b9fbde096 --- /dev/null +++ b/.isort.cfg @@ -0,0 +1,2 @@ +[settings] +profile=black \ No newline at end of file diff --git a/docs/code-quality/index.rst b/docs/code-quality/index.rst index c31696bba2d4..305d5719a021 100644 --- a/docs/code-quality/index.rst +++ b/docs/code-quality/index.rst @@ -90,16 +90,27 @@ In this document, we try to list these all tools. - Meta bug - More info - Upstream - * - ruff - - Yes - - `bug 1811850 `__ - - :ref:`ruff` - - https://github.com/charliermarsh/ruff + * - Flake8 + - Yes (with `autopep8 `_) + - `bug 1155970 `__ + - :ref:`Flake8` + - http://flake8.pycqa.org/ * - black - Yes - `bug 1555560 `__ - :ref:`black` - https://black.readthedocs.io/en/stable + * - pylint + - + - `bug 1623024 `__ + - :ref:`pylint` + - https://www.pylint.org/ + * - Python 2/3 compatibility check + - + - `bug 1496527 `__ + - :ref:`Python 2/3 compatibility check` + - + .. list-table:: Rust :widths: 20 20 20 20 20 diff --git a/docs/code-quality/lint/linters/flake8.rst b/docs/code-quality/lint/linters/flake8.rst new file mode 100644 index 000000000000..0e46d33ab026 --- /dev/null +++ b/docs/code-quality/lint/linters/flake8.rst @@ -0,0 +1,46 @@ +Flake8 +====== + +`Flake8 `__ is a popular lint wrapper for python. Under the hood, it runs three other tools and +combines their results: + +* `pep8 `__ for checking style +* `pyflakes `__ for checking syntax +* `mccabe `__ for checking complexity + + +Run Locally +----------- + +The mozlint integration of flake8 can be run using mach: + +.. parsed-literal:: + + $ mach lint --linter flake8 + +Alternatively, omit the ``--linter flake8`` and run all configured linters, which will include +flake8. + + +Configuration +------------- + +Path configuration is defined in the root `.flake8`_ file. Please update this file rather than +``tools/lint/flake8.yml`` if you need to exclude a new path. For an overview of the supported +configuration, see `flake8's documentation`_. + +.. _.flake8: https://searchfox.org/mozilla-central/source/.flake8 +.. _flake8's documentation: https://flake8.pycqa.org/en/latest/user/configuration.html + +Autofix +------- + +The flake8 linter provides a ``--fix`` option. It is based on `autopep8 `__. +Please note that autopep8 does NOT fix all issues reported by flake8. + + +Sources +------- + +* `Configuration (YAML) `_ +* `Source `_ diff --git a/docs/code-quality/lint/linters/pylint.rst b/docs/code-quality/lint/linters/pylint.rst new file mode 100644 index 000000000000..603f80516aba --- /dev/null +++ b/docs/code-quality/lint/linters/pylint.rst @@ -0,0 +1,33 @@ +pylint +====== + +`pylint `__ is a popular linter for python. It is now the default python +linter in VS Code. + +Please note that we also have :ref:`Flake8` available as a linter. + +Run Locally +----------- + +The mozlint integration of pylint can be run using mach: + +.. parsed-literal:: + + $ mach lint --linter pylint + + + +Configuration +------------- + +To enable pylint on new directory, add the path to the include +section in the `pylint.yml `_ file. + +We enabled the same Pylint rules as `VS Code `_. +See in `pylint.py `_ for the full list + +Sources +------- + +* `Configuration (YAML) `_ +* `Source `_ diff --git a/docs/code-quality/lint/linters/ruff.rst b/docs/code-quality/lint/linters/ruff.rst deleted file mode 100644 index 359e8dcbf686..000000000000 --- a/docs/code-quality/lint/linters/ruff.rst +++ /dev/null @@ -1,44 +0,0 @@ -Ruff -==== - -`Ruff `_ is an extremely fast Python -linter and formatter, written in Rust. It can process all of mozilla-central in -under a second, and implements rule sets from a large array of Python linters -and formatters, including: - -* flake8 (pycodestyle, pyflakes and mccabe) -* isort -* pylint -* pyupgrade -* and many many more! - -Run Locally ------------ - -The mozlint integration of ruff can be run using mach: - -.. parsed-literal:: - - $ mach lint --linter ruff - - -Configuration -------------- - -Ruff is configured in the root `pyproject.toml`_ file. Additionally, ruff will -pick up any ``pyproject.toml`` or ``ruff.toml`` files in subdirectories. The -settings in these files will only apply to files contained within these -subdirs. For more details on configuration discovery, see the `configuration -documentation`_. - -For a list of options, see the `settings documentation`_. - -Sources -------- - -* `Configuration (YAML) `_ -* `Source `_ - -.. _pyproject.toml: https://searchfox.org/mozilla-central/source/pyproject.toml -.. _configuration documentation: https://beta.ruff.rs/docs/configuration/ -.. _settings documentation: https://beta.ruff.rs/docs/settings/ diff --git a/js/src/gdb/mozilla/ExecutableAllocator.py b/js/src/gdb/mozilla/ExecutableAllocator.py index 5187e2d1f182..e82b1a186da4 100644 --- a/js/src/gdb/mozilla/ExecutableAllocator.py +++ b/js/src/gdb/mozilla/ExecutableAllocator.py @@ -9,7 +9,6 @@ allocated by the Jits. """ import gdb - import mozilla.prettyprinters from mozilla.prettyprinters import pretty_printer, ptr_pretty_printer diff --git a/js/src/gdb/mozilla/GCCellPtr.py b/js/src/gdb/mozilla/GCCellPtr.py index e42ecfa8939b..ce02a94dfe8b 100644 --- a/js/src/gdb/mozilla/GCCellPtr.py +++ b/js/src/gdb/mozilla/GCCellPtr.py @@ -5,7 +5,6 @@ # Pretty-printers for GCCellPtr values. import gdb - import mozilla.prettyprinters from mozilla.prettyprinters import pretty_printer diff --git a/js/src/gdb/mozilla/Interpreter.py b/js/src/gdb/mozilla/Interpreter.py index cc7cd7372675..febf92b86deb 100644 --- a/js/src/gdb/mozilla/Interpreter.py +++ b/js/src/gdb/mozilla/Interpreter.py @@ -5,7 +5,6 @@ # Pretty-printers for InterpreterRegs. import gdb - import mozilla.prettyprinters as prettyprinters prettyprinters.clear_module_printers(__name__) diff --git a/js/src/gdb/mozilla/IonGraph.py b/js/src/gdb/mozilla/IonGraph.py index 639baf3acee0..e5e235c59485 100644 --- a/js/src/gdb/mozilla/IonGraph.py +++ b/js/src/gdb/mozilla/IonGraph.py @@ -17,7 +17,6 @@ import tempfile import time import gdb - import mozilla.prettyprinters from mozilla.prettyprinters import pretty_printer diff --git a/js/src/gdb/mozilla/JSObject.py b/js/src/gdb/mozilla/JSObject.py index 95accc93b957..006f93a89747 100644 --- a/js/src/gdb/mozilla/JSObject.py +++ b/js/src/gdb/mozilla/JSObject.py @@ -7,7 +7,6 @@ import re import gdb - import mozilla.prettyprinters as prettyprinters from mozilla.CellHeader import get_header_ptr from mozilla.jsval import JSValue diff --git a/js/src/gdb/mozilla/JSString.py b/js/src/gdb/mozilla/JSString.py index 3c758e0352e9..afcd3207408f 100644 --- a/js/src/gdb/mozilla/JSString.py +++ b/js/src/gdb/mozilla/JSString.py @@ -5,7 +5,6 @@ # Pretty-printers for SpiderMonkey strings. import gdb - import mozilla.prettyprinters from mozilla.CellHeader import get_header_length_and_flags from mozilla.prettyprinters import ptr_pretty_printer diff --git a/js/src/gdb/mozilla/autoload.py b/js/src/gdb/mozilla/autoload.py index bc62e0455584..5e7347d4e113 100644 --- a/js/src/gdb/mozilla/autoload.py +++ b/js/src/gdb/mozilla/autoload.py @@ -8,7 +8,6 @@ print("Loading JavaScript value pretty-printers; see js/src/gdb/README.") print("If they cause trouble, type: disable pretty-printer .* SpiderMonkey") import gdb.printing - import mozilla.ExecutableAllocator # Import the pretty-printer modules. As a side effect, loading these diff --git a/js/src/gdb/mozilla/jsop.py b/js/src/gdb/mozilla/jsop.py index 635acb752856..ae21aad5f638 100644 --- a/js/src/gdb/mozilla/jsop.py +++ b/js/src/gdb/mozilla/jsop.py @@ -6,7 +6,6 @@ import gdb import gdb.types - import mozilla.prettyprinters from mozilla.prettyprinters import pretty_printer, ptr_pretty_printer diff --git a/js/src/gdb/mozilla/jsval.py b/js/src/gdb/mozilla/jsval.py index d01a5ceacc41..27a47115915a 100644 --- a/js/src/gdb/mozilla/jsval.py +++ b/js/src/gdb/mozilla/jsval.py @@ -8,7 +8,6 @@ import struct import gdb import gdb.types - import mozilla.prettyprinters from mozilla.prettyprinters import pretty_printer diff --git a/js/src/gdb/mozilla/unwind.py b/js/src/gdb/mozilla/unwind.py index 8ad4393b7ae5..4b1ffa801490 100644 --- a/js/src/gdb/mozilla/unwind.py +++ b/js/src/gdb/mozilla/unwind.py @@ -9,7 +9,6 @@ import platform import gdb import gdb.types from gdb.FrameDecorator import FrameDecorator - from mozilla.JSObject import get_function_name, get_function_script from mozilla.prettyprinters import TypeCache diff --git a/pyproject.toml b/pyproject.toml deleted file mode 100644 index 38b62cab3a2d..000000000000 --- a/pyproject.toml +++ /dev/null @@ -1,131 +0,0 @@ -[tool.ruff] -line-length = 99 -# See https://beta.ruff.rs/docs/rules/ for a full list of rules. -select = [ - "E", "W", # pycodestyle - "F", # pyflakes - "I", # isort - "PL", # pylint -] -ignore = [ - # These should be triaged and either fixed or moved to the list below. - "E713", "E714", "W605", - - # These are intentionally ignored (not necessarily for good reason). - "E741", - - # These are handled by black. - "E1", "E4", "E5", "W2", "W5" -] -builtins = ["gdb"] -exclude = [ - # These paths should be triaged and either fixed or moved to the list below. - "devtools/shared", - "dom/bindings/Codegen.py", - "dom/bindings/parser/WebIDL.py", - "dom/bindings/parser/tests/test_arraybuffer.py", - "dom/bindings/parser/tests/test_securecontext_extended_attribute.py", - "gfx/tests", - "ipc/ipdl/ipdl", - "layout/base/tests/marionette", - "layout/reftests/border-image", - "layout/reftests/fonts", - "layout/reftests/w3c-css", - "layout/style", - "media/libdav1d/generate_source.py", - "moz.configure", - "netwerk/dns/prepare_tlds.py", - "netwerk/protocol/http/make_incoming_tables.py", - "python/l10n/fluent_migrations", - "security/manager/ssl/tests/unit", - "servo/components/style", - "testing/condprofile/condprof/android.py", - "testing/condprofile/condprof/creator.py", - "testing/condprofile/condprof/desktop.py", - "testing/condprofile/condprof/runner.py", - "testing/condprofile/condprof/scenarii/heavy.py", - "testing/condprofile/condprof/scenarii/settled.py", - "testing/condprofile/condprof/scenarii/synced.p", - "testing/condprofile/condprof/helpers.py", - "testing/jsshell/benchmark.py", - "testing/marionette/mach_commands.py", - "testing/mozharness/docs", - "testing/mozharness/examples", - "testing/mozharness/external_tools", - "testing/mozharness/mach_commands.py", - "testing/mozharness/manifestparser", - "testing/mozharness/mozprocess", - "testing/mozharness/setup.py", - "testing/parse_build_tests_ccov.py", - "testing/runtimes/writeruntimes.py", - "testing/tools/iceserver/iceserver.py", - "testing/tools/websocketprocessbridge/websocketprocessbridge.py", - "toolkit/components/featuregates", - "toolkit/content/tests/chrome/file_about_networking_wsh.py", - "toolkit/library/build/dependentlibs.py", - "toolkit/locales/generate_update_locale.py", - "toolkit/mozapps", - "toolkit/moz.configure", - "toolkit/nss.configure", - - # mako files are not really python files - "*.mako.py", - - # These paths are intentionally excluded (not necessarily for good reason). - "build/moz.configure/*.configure", - "build/pymake/", - "browser/extensions/mortar/ppapi/", - "browser/moz.configure", - "dom/canvas/test/webgl-conf/checkout/closure-library/", - "editor/libeditor/tests/browserscope/", - "intl/icu/", - "ipc/chromium/src/third_party/", - "js/*.configure", - "gfx/angle/", - "gfx/harfbuzz", - "gfx/skia/", - "memory/moz.configure", - "mobile/android/*.configure", - "node_modules", - "python/mozbuild/mozbuild/test/configure/data", - "security/nss/", - "testing/marionette/harness/marionette_harness/runner/mixins", - "testing/marionette/harness/marionette_harness/tests", - "testing/mochitest/pywebsocket3", - "testing/mozharness/configs/test/test_malformed.py", - "testing/web-platform/tests", - "tools/lint/test/files", - "tools/crashreporter/*.configure", - ".ycm_extra_conf.py", -] - -[tool.ruff.per-file-ignores] -# These paths are intentionally excluded. -"dom/bindings/Configuration.py" = ["PLC3002"] -"ipc/ipdl/*" = ["F403", "F405"] -"layout/tools/reftest/selftest/conftest.py" = ["F811"] -# cpp_eclipse has a lot of multi-line embedded XML which exceeds line length -"python/mozbuild/mozbuild/backend/cpp_eclipse.py" = ["E501"] -"testing/firefox-ui/**/__init__.py" = ["F401"] -"testing/marionette/**/__init__.py" = ["F401"] -"testing/mochitest/tests/python/conftest.py" = ["F811"] -"testing/mozbase/manifestparser/tests/test_filters.py" = ["E731"] -"testing/mozbase/mozinfo/mozinfo/mozinfo.py" = ["PLE0605"] -"testing/mozbase/mozlog/tests/test_formatters.py" = ["E501"] -"testing/mozharness/configs/*" = ["E501"] -"**/*.configure" = ["F821"] -# These paths contain Python-2 only syntax. -"build/compare-mozconfig/compare-mozconfigs.py" = ["F821"] -"build/midl.py" = ["F821"] -"build/pgo/genpgocert.py" = ["F821"] -"config/MozZipFile.py" = ["F821"] -"config/check_source_count.py" = ["F821"] -"config/tests/unitMozZipFile.py" = ["F821"] -"ipc/pull-chromium.py" = ["F633"] -"js/src/**" = ["F633", "F821"] -"python/mozbuild/mozbuild/action/dump_env.py" = ["F821"] -"python/mozbuild/mozbuild/dotproperties.py" = ["F821"] -"python/mozbuild/mozbuild/testing.py" = ["F821"] -"python/mozbuild/mozbuild/util.py" = ["F821"] -"testing/mozharness/mozharness/mozilla/testing/android.py" = ["F821"] -"testing/mochitest/runtests.py" = ["F821"] diff --git a/python/gdbpp/gdbpp/__init__.py b/python/gdbpp/gdbpp/__init__.py index 376061b679e9..7a7681aa6de3 100644 --- a/python/gdbpp/gdbpp/__init__.py +++ b/python/gdbpp/gdbpp/__init__.py @@ -20,12 +20,12 @@ class GeckoPrettyPrinter(object): return wrapped -import gdbpp.enumset # noqa: F401 -import gdbpp.linkedlist # noqa: F401 -import gdbpp.owningthread # noqa: F401 -import gdbpp.smartptr # noqa: F401 -import gdbpp.string # noqa: F401 -import gdbpp.tarray # noqa: F401 -import gdbpp.thashtable # noqa: F401 +import gdbpp.enumset # NOQA: F401 +import gdbpp.linkedlist # NOQA: F401 +import gdbpp.owningthread # NOQA: F401 +import gdbpp.smartptr # NOQA: F401 +import gdbpp.string # NOQA: F401 +import gdbpp.tarray # NOQA: F401 +import gdbpp.thashtable # NOQA: F401 gdb.printing.register_pretty_printer(None, GeckoPrettyPrinter.pp) diff --git a/python/gdbpp/gdbpp/enumset.py b/python/gdbpp/gdbpp/enumset.py index c36e863627dd..6023364eb9e0 100644 --- a/python/gdbpp/gdbpp/enumset.py +++ b/python/gdbpp/gdbpp/enumset.py @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import gdb - from gdbpp import GeckoPrettyPrinter diff --git a/python/gdbpp/gdbpp/owningthread.py b/python/gdbpp/gdbpp/owningthread.py index 52055b3c99ff..cdf0b30c82b3 100644 --- a/python/gdbpp/gdbpp/owningthread.py +++ b/python/gdbpp/gdbpp/owningthread.py @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import gdb - from gdbpp import GeckoPrettyPrinter diff --git a/python/gdbpp/gdbpp/thashtable.py b/python/gdbpp/gdbpp/thashtable.py index 8b0294acf60d..5775f2994727 100644 --- a/python/gdbpp/gdbpp/thashtable.py +++ b/python/gdbpp/gdbpp/thashtable.py @@ -5,7 +5,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import gdb - from gdbpp import GeckoPrettyPrinter diff --git a/python/lldbutils/.isort.cfg b/python/lldbutils/.isort.cfg new file mode 100644 index 000000000000..568338b79f5d --- /dev/null +++ b/python/lldbutils/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=lldbutils \ No newline at end of file diff --git a/python/lldbutils/.ruff.toml b/python/lldbutils/.ruff.toml deleted file mode 100644 index 7c7717fa1396..000000000000 --- a/python/lldbutils/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["lldbutils"] diff --git a/python/mach/.isort.cfg b/python/mach/.isort.cfg new file mode 100644 index 000000000000..aa7eca425027 --- /dev/null +++ b/python/mach/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mach \ No newline at end of file diff --git a/python/mach/.ruff.toml b/python/mach/.ruff.toml deleted file mode 100644 index 82b1a04648bb..000000000000 --- a/python/mach/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mach"] diff --git a/python/mach/mach/commands/settings.py b/python/mach/mach/commands/settings.py index 8e168a3921ca..474790cd426a 100644 --- a/python/mach/mach/commands/settings.py +++ b/python/mach/mach/commands/settings.py @@ -7,7 +7,6 @@ from textwrap import TextWrapper from mach.config import TYPE_CLASSES from mach.decorators import Command, CommandArgument - # Interact with settings for mach. # Currently, we only provide functionality to view what settings are diff --git a/python/mach/mach/test/test_site.py b/python/mach/mach/test/test_site.py index d7c3d8c489ba..df3a5acd739e 100644 --- a/python/mach/mach/test/test_site.py +++ b/python/mach/mach/test/test_site.py @@ -5,7 +5,7 @@ import os from unittest import mock -import pytest +import pytest as pytest from buildconfig import topsrcdir from mozunit import main diff --git a/python/mozboot/.isort.cfg b/python/mozboot/.isort.cfg new file mode 100644 index 000000000000..875efb0395d6 --- /dev/null +++ b/python/mozboot/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozboot \ No newline at end of file diff --git a/python/mozboot/.ruff.toml b/python/mozboot/.ruff.toml deleted file mode 100644 index 648a1255cc5a..000000000000 --- a/python/mozboot/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozboot"] diff --git a/python/mozbuild/.isort.cfg b/python/mozbuild/.isort.cfg new file mode 100644 index 000000000000..30fe17b73ded --- /dev/null +++ b/python/mozbuild/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozbuild \ No newline at end of file diff --git a/python/mozbuild/.ruff.toml b/python/mozbuild/.ruff.toml deleted file mode 100644 index ba54f854aaf6..000000000000 --- a/python/mozbuild/.ruff.toml +++ /dev/null @@ -1,9 +0,0 @@ -extend = "../../pyproject.toml" -src = [ - # Treat direct imports in the test modules as first party. - "mozpack/test", - "mozbuild/test", -] - -[isort] -known-first-party = ["mozbuild"] diff --git a/python/mozbuild/mozbuild/compilation/codecomplete.py b/python/mozbuild/mozbuild/compilation/codecomplete.py index b5a466b72928..497061e983bd 100644 --- a/python/mozbuild/mozbuild/compilation/codecomplete.py +++ b/python/mozbuild/mozbuild/compilation/codecomplete.py @@ -9,7 +9,6 @@ from mach.decorators import Command, CommandArgument from mozbuild.shellutil import quote as shell_quote from mozbuild.shellutil import split as shell_split - # Instropection commands. diff --git a/python/mozbuild/mozbuild/configure/options.py b/python/mozbuild/mozbuild/configure/options.py index cc3b4516ea6b..4b623af5fad2 100644 --- a/python/mozbuild/mozbuild/configure/options.py +++ b/python/mozbuild/mozbuild/configure/options.py @@ -147,7 +147,7 @@ class NegativeOptionValue(OptionValue): return super(NegativeOptionValue, cls).__new__(cls, origin=origin) def __init__(self, origin="unknown"): - super(NegativeOptionValue, self).__init__(origin=origin) + return super(NegativeOptionValue, self).__init__(origin=origin) class InvalidOptionError(Exception): diff --git a/python/mozbuild/mozbuild/mach_commands.py b/python/mozbuild/mozbuild/mach_commands.py index 25a785fc493a..0a4e6550d9b6 100644 --- a/python/mozbuild/mozbuild/mach_commands.py +++ b/python/mozbuild/mozbuild/mach_commands.py @@ -32,12 +32,9 @@ from mach.decorators import ( from voluptuous import All, Boolean, Required, Schema import mozbuild.settings # noqa need @SettingsProvider hook to execute -from mozbuild.base import ( - BinaryNotFoundException, - BuildEnvironmentNotFoundException, - MozbuildObject, -) +from mozbuild.base import BinaryNotFoundException, BuildEnvironmentNotFoundException from mozbuild.base import MachCommandConditions as conditions +from mozbuild.base import MozbuildObject from mozbuild.util import MOZBUILD_METRICS_PATH here = os.path.abspath(os.path.dirname(__file__)) diff --git a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py index ebca6576681d..c82900eed12c 100644 --- a/python/mozbuild/mozbuild/test/configure/test_checks_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_checks_configure.py @@ -8,11 +8,11 @@ import textwrap import unittest from buildconfig import topsrcdir +from common import ConfigureTestSandbox, ensure_exe_extension, fake_short_path from mozpack import path as mozpath from mozunit import MockedOpen, main from six import StringIO -from common import ConfigureTestSandbox, ensure_exe_extension, fake_short_path from mozbuild.configure import ConfigureError, ConfigureSandbox from mozbuild.shellutil import quote as shell_quote from mozbuild.util import exec_ diff --git a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py index 37988d535f73..92f4dc664957 100644 --- a/python/mozbuild/mozbuild/test/configure/test_compile_checks.py +++ b/python/mozbuild/mozbuild/test/configure/test_compile_checks.py @@ -8,11 +8,11 @@ import unittest import mozpack.path as mozpath from buildconfig import topsrcdir +from common import ConfigureTestSandbox from mozunit import main from six import StringIO from test_toolchain_helpers import FakeCompiler -from common import ConfigureTestSandbox from mozbuild.util import exec_ diff --git a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py index 22129a397098..f9acfb704704 100644 --- a/python/mozbuild/mozbuild/test/configure/test_moz_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_moz_configure.py @@ -2,9 +2,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. +from common import BaseConfigureTest, ConfigureTestSandbox from mozunit import main -from common import BaseConfigureTest, ConfigureTestSandbox from mozbuild.util import ReadOnlyNamespace, exec_, memoized_property diff --git a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py index 0e142c2a7f12..25f0b65574f9 100644 --- a/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_toolchain_configure.py @@ -6,13 +6,13 @@ import logging import os import six +from common import BaseConfigureTest from mozboot.util import MINIMUM_RUST_VERSION from mozpack import path as mozpath from mozunit import main from six import StringIO from test_toolchain_helpers import CompilerResult, FakeCompiler, PrependFlags -from common import BaseConfigureTest from mozbuild.configure.util import Version from mozbuild.util import ReadOnlyNamespace, memoize diff --git a/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py b/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py index e6b96b3627ca..dab8109e2ca8 100644 --- a/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py +++ b/python/mozbuild/mozbuild/test/configure/test_toolkit_moz_configure.py @@ -5,10 +5,10 @@ import os from buildconfig import topsrcdir +from common import BaseConfigureTest from mozpack import path as mozpath from mozunit import MockedOpen, main -from common import BaseConfigureTest from mozbuild.configure.options import InvalidOptionError diff --git a/python/mozbuild/mozbuild/test/configure/test_util.py b/python/mozbuild/mozbuild/test/configure/test_util.py index 81c2e2a8bf21..39ea503453b9 100644 --- a/python/mozbuild/mozbuild/test/configure/test_util.py +++ b/python/mozbuild/mozbuild/test/configure/test_util.py @@ -11,11 +11,11 @@ import unittest import six from buildconfig import topsrcdir +from common import ConfigureTestSandbox from mozpack import path as mozpath from mozunit import main from six import StringIO -from common import ConfigureTestSandbox from mozbuild.configure import ConfigureSandbox from mozbuild.configure.util import ( ConfigureOutputHandler, diff --git a/python/mozbuild/mozbuild/util.py b/python/mozbuild/mozbuild/util.py index 3e1e0dbde4dc..d0c72a07d001 100644 --- a/python/mozbuild/mozbuild/util.py +++ b/python/mozbuild/mozbuild/util.py @@ -430,7 +430,7 @@ class List(list): raise ValueError("List can only be created from other list instances.") self._kwargs = kwargs - super(List, self).__init__(iterable) + return super(List, self).__init__(iterable) def extend(self, l): if not isinstance(l, list): diff --git a/python/mozbuild/mozpack/chrome/flags.py b/python/mozbuild/mozpack/chrome/flags.py index 6b096c862aaa..08e975dbe1d1 100644 --- a/python/mozbuild/mozpack/chrome/flags.py +++ b/python/mozbuild/mozpack/chrome/flags.py @@ -6,9 +6,8 @@ import re from collections import OrderedDict import six -from packaging.version import Version - from mozpack.errors import errors +from packaging.version import Version class Flag(object): diff --git a/python/mozbuild/mozpack/chrome/manifest.py b/python/mozbuild/mozpack/chrome/manifest.py index 14c11d4c1daa..badbd2fd9ceb 100644 --- a/python/mozbuild/mozpack/chrome/manifest.py +++ b/python/mozbuild/mozpack/chrome/manifest.py @@ -5,12 +5,11 @@ import os import re -import six -from six.moves.urllib.parse import urlparse - import mozpack.path as mozpath +import six from mozpack.chrome.flags import Flags from mozpack.errors import errors +from six.moves.urllib.parse import urlparse class ManifestEntry(object): diff --git a/python/mozbuild/mozpack/copier.py b/python/mozbuild/mozpack/copier.py index c042e5432f28..bf222abbcaf2 100644 --- a/python/mozbuild/mozpack/copier.py +++ b/python/mozbuild/mozpack/copier.py @@ -9,9 +9,8 @@ import stat import sys from collections import Counter, OrderedDict, defaultdict -import six - import mozpack.path as mozpath +import six from mozpack.errors import errors from mozpack.files import BaseFile, Dest diff --git a/python/mozbuild/mozpack/files.py b/python/mozbuild/mozpack/files.py index 691c248b02b3..ba8c5d9f1366 100644 --- a/python/mozbuild/mozpack/files.py +++ b/python/mozbuild/mozpack/files.py @@ -18,18 +18,18 @@ from itertools import chain, takewhile from tarfile import TarFile, TarInfo from tempfile import NamedTemporaryFile, mkstemp +import mozpack.path as mozpath import six from jsmin import JavascriptMinify - -import mozbuild.makeutil as makeutil -import mozpack.path as mozpath -from mozbuild.preprocessor import Preprocessor -from mozbuild.util import FileAvoidWrite, ensure_unicode, memoize from mozpack.chrome.manifest import ManifestEntry, ManifestInterfaces from mozpack.errors import ErrorMessage, errors from mozpack.executables import elfhack, is_executable, may_elfhack, may_strip, strip from mozpack.mozjar import JarReader +import mozbuild.makeutil as makeutil +from mozbuild.preprocessor import Preprocessor +from mozbuild.util import FileAvoidWrite, ensure_unicode, memoize + try: import hglib except ImportError: diff --git a/python/mozbuild/mozpack/manifests.py b/python/mozbuild/mozpack/manifests.py index 2df6c729eaf0..32ec3f73630c 100644 --- a/python/mozbuild/mozpack/manifests.py +++ b/python/mozbuild/mozpack/manifests.py @@ -5,9 +5,8 @@ import json from contextlib import contextmanager -import six - import mozpack.path as mozpath +import six from .files import ( AbsoluteSymlinkFile, diff --git a/python/mozbuild/mozpack/mozjar.py b/python/mozbuild/mozpack/mozjar.py index 6500ebfceccf..c98412013723 100644 --- a/python/mozbuild/mozpack/mozjar.py +++ b/python/mozbuild/mozpack/mozjar.py @@ -9,9 +9,9 @@ from collections import OrderedDict from io import BytesIO, UnsupportedOperation from zipfile import ZIP_DEFLATED, ZIP_STORED +import mozpack.path as mozpath import six -import mozpack.path as mozpath from mozbuild.util import ensure_bytes JAR_STORED = ZIP_STORED diff --git a/python/mozbuild/mozpack/packager/__init__.py b/python/mozbuild/mozpack/packager/__init__.py index 83b12e469643..b118b6a2d10d 100644 --- a/python/mozbuild/mozpack/packager/__init__.py +++ b/python/mozbuild/mozpack/packager/__init__.py @@ -8,10 +8,8 @@ import os import re from collections import deque -import six - import mozpack.path as mozpath -from mozbuild.preprocessor import Preprocessor +import six from mozpack.chrome.manifest import ( Manifest, ManifestBinaryComponent, @@ -22,6 +20,8 @@ from mozpack.chrome.manifest import ( ) from mozpack.errors import errors +from mozbuild.preprocessor import Preprocessor + class Component(object): """ diff --git a/python/mozbuild/mozpack/packager/formats.py b/python/mozbuild/mozpack/packager/formats.py index 95a6dee2f699..db5dc0c5174b 100644 --- a/python/mozbuild/mozpack/packager/formats.py +++ b/python/mozbuild/mozpack/packager/formats.py @@ -2,8 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from six.moves.urllib.parse import urlparse - import mozpack.path as mozpath from mozpack.chrome.manifest import ( Manifest, @@ -16,6 +14,7 @@ from mozpack.chrome.manifest import ( from mozpack.copier import FileRegistry, FileRegistrySubtree, Jarrer from mozpack.errors import errors from mozpack.files import ManifestFile +from six.moves.urllib.parse import urlparse """ Formatters are classes receiving packaging instructions and creating the diff --git a/python/mozbuild/mozpack/packager/l10n.py b/python/mozbuild/mozpack/packager/l10n.py index 76871e15cdfe..a3b628ac9f2f 100644 --- a/python/mozbuild/mozpack/packager/l10n.py +++ b/python/mozbuild/mozpack/packager/l10n.py @@ -10,10 +10,9 @@ directory. import json import os +import mozpack.path as mozpath import six from createprecomplete import generate_precomplete - -import mozpack.path as mozpath from mozpack.chrome.manifest import ( Manifest, ManifestChrome, diff --git a/python/mozbuild/mozpack/packager/unpack.py b/python/mozbuild/mozpack/packager/unpack.py index dff295eb9ba5..f5729a3e91bd 100644 --- a/python/mozbuild/mozpack/packager/unpack.py +++ b/python/mozbuild/mozpack/packager/unpack.py @@ -4,8 +4,6 @@ import codecs -from six.moves.urllib.parse import urlparse - import mozpack.path as mozpath from mozpack.chrome.manifest import ( ManifestEntryWithRelPath, @@ -18,6 +16,7 @@ from mozpack.files import BaseFinder, DeflatedFile, FileFinder, ManifestFile from mozpack.mozjar import JarReader from mozpack.packager import SimplePackager from mozpack.packager.formats import FlatFormatter +from six.moves.urllib.parse import urlparse class UnpackFinder(BaseFinder): diff --git a/python/mozbuild/mozpack/test/test_archive.py b/python/mozbuild/mozpack/test/test_archive.py index 3417f279dff0..9cf14768e469 100644 --- a/python/mozbuild/mozpack/test/test_archive.py +++ b/python/mozbuild/mozpack/test/test_archive.py @@ -11,8 +11,6 @@ import tempfile import unittest import pytest -from mozunit import main - from mozpack.archive import ( DEFAULT_MTIME, create_tar_bz2_from_files, @@ -20,6 +18,7 @@ from mozpack.archive import ( create_tar_gz_from_files, ) from mozpack.files import GeneratedFile +from mozunit import main MODE_STANDARD = stat.S_IRUSR | stat.S_IWUSR | stat.S_IRGRP | stat.S_IROTH diff --git a/python/mozbuild/mozpack/test/test_chrome_flags.py b/python/mozbuild/mozpack/test/test_chrome_flags.py index 4f1a968dc2e6..340484ad2968 100644 --- a/python/mozbuild/mozpack/test/test_chrome_flags.py +++ b/python/mozbuild/mozpack/test/test_chrome_flags.py @@ -5,7 +5,6 @@ import unittest import mozunit - from mozpack.chrome.flags import Flag, Flags, StringFlag, VersionFlag from mozpack.errors import ErrorMessage diff --git a/python/mozbuild/mozpack/test/test_chrome_manifest.py b/python/mozbuild/mozpack/test/test_chrome_manifest.py index c1d5826bbc87..52aa5705e849 100644 --- a/python/mozbuild/mozpack/test/test_chrome_manifest.py +++ b/python/mozbuild/mozpack/test/test_chrome_manifest.py @@ -6,7 +6,6 @@ import os import unittest import mozunit - from mozpack.chrome.manifest import ( MANIFESTS_TYPES, Manifest, diff --git a/python/mozbuild/mozpack/test/test_copier.py b/python/mozbuild/mozpack/test/test_copier.py index 60ebd2c1e9e1..ea2b0eae80f8 100644 --- a/python/mozbuild/mozpack/test/test_copier.py +++ b/python/mozbuild/mozpack/test/test_copier.py @@ -6,10 +6,9 @@ import os import stat import unittest +import mozpack.path as mozpath import mozunit import six - -import mozpack.path as mozpath from mozpack.copier import FileCopier, FileRegistry, FileRegistrySubtree, Jarrer from mozpack.errors import ErrorMessage from mozpack.files import ExistingFile, GeneratedFile diff --git a/python/mozbuild/mozpack/test/test_errors.py b/python/mozbuild/mozpack/test/test_errors.py index 411b1b54c3b1..31e3922c9657 100644 --- a/python/mozbuild/mozpack/test/test_errors.py +++ b/python/mozbuild/mozpack/test/test_errors.py @@ -7,7 +7,6 @@ import unittest import mozunit import six - from mozpack.errors import AccumulatedErrors, ErrorMessage, errors diff --git a/python/mozbuild/mozpack/test/test_files.py b/python/mozbuild/mozpack/test/test_files.py index 1c86f2e0cca0..07edad79592e 100644 --- a/python/mozbuild/mozpack/test/test_files.py +++ b/python/mozbuild/mozpack/test/test_files.py @@ -2,7 +2,6 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from mozbuild.util import ensure_bytes, ensureParentDir from mozpack.errors import ErrorMessage, errors from mozpack.files import ( AbsoluteSymlinkFile, @@ -25,6 +24,8 @@ from mozpack.files import ( TarFinder, ) +from mozbuild.util import ensure_bytes, ensureParentDir + # We don't have hglib installed everywhere. try: import hglib @@ -41,10 +42,9 @@ from io import BytesIO from tempfile import mkdtemp import mozfile +import mozpack.path as mozpath import mozunit import six - -import mozpack.path as mozpath from mozpack.chrome.manifest import ( ManifestContent, ManifestLocale, diff --git a/python/mozbuild/mozpack/test/test_manifests.py b/python/mozbuild/mozpack/test/test_manifests.py index a5db53b58ce4..ee5e6220b49f 100644 --- a/python/mozbuild/mozpack/test/test_manifests.py +++ b/python/mozbuild/mozpack/test/test_manifests.py @@ -5,7 +5,6 @@ import os import mozunit - from mozpack.copier import FileCopier, FileRegistry from mozpack.manifests import InstallManifest, UnreadableInstallManifest from mozpack.test.test_files import TestWithTmpDir diff --git a/python/mozbuild/mozpack/test/test_mozjar.py b/python/mozbuild/mozpack/test/test_mozjar.py index e96c59238f78..7a17501cc5fb 100644 --- a/python/mozbuild/mozpack/test/test_mozjar.py +++ b/python/mozbuild/mozpack/test/test_mozjar.py @@ -6,10 +6,9 @@ import os import unittest from collections import OrderedDict +import mozpack.path as mozpath import mozunit import six - -import mozpack.path as mozpath from mozpack.files import FileFinder from mozpack.mozjar import ( Deflater, diff --git a/python/mozbuild/mozpack/test/test_packager.py b/python/mozbuild/mozpack/test/test_packager.py index 266902ebb250..3e5ae5cdcb56 100644 --- a/python/mozbuild/mozpack/test/test_packager.py +++ b/python/mozbuild/mozpack/test/test_packager.py @@ -5,12 +5,9 @@ import os import unittest +import mozpack.path as mozpath import mozunit from buildconfig import topobjdir -from mozunit import MockedOpen - -import mozpack.path as mozpath -from mozbuild.preprocessor import Preprocessor from mozpack.chrome.manifest import ( ManifestBinaryComponent, ManifestContent, @@ -25,6 +22,9 @@ from mozpack.packager import ( SimplePackager, preprocess_manifest, ) +from mozunit import MockedOpen + +from mozbuild.preprocessor import Preprocessor MANIFEST = """ bar/* diff --git a/python/mozbuild/mozpack/test/test_packager_formats.py b/python/mozbuild/mozpack/test/test_packager_formats.py index b09971a1028e..e9bc56c85683 100644 --- a/python/mozbuild/mozpack/test/test_packager_formats.py +++ b/python/mozbuild/mozpack/test/test_packager_formats.py @@ -5,10 +5,9 @@ import unittest from itertools import chain +import mozpack.path as mozpath import mozunit import six - -import mozpack.path as mozpath from mozpack.chrome.manifest import ( ManifestBinaryComponent, ManifestComponent, diff --git a/python/mozbuild/mozpack/test/test_packager_l10n.py b/python/mozbuild/mozpack/test/test_packager_l10n.py index 0714ae3252d4..caef92a3c01a 100644 --- a/python/mozbuild/mozpack/test/test_packager_l10n.py +++ b/python/mozbuild/mozpack/test/test_packager_l10n.py @@ -6,7 +6,6 @@ import unittest import mozunit import six - from mozpack.chrome.manifest import Manifest, ManifestContent, ManifestLocale from mozpack.copier import FileRegistry from mozpack.files import GeneratedFile, ManifestFile diff --git a/python/mozbuild/mozpack/test/test_packager_unpack.py b/python/mozbuild/mozpack/test/test_packager_unpack.py index 57a2d71edac7..1f679e3a0df5 100644 --- a/python/mozbuild/mozpack/test/test_packager_unpack.py +++ b/python/mozbuild/mozpack/test/test_packager_unpack.py @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import mozunit - from mozpack.copier import FileCopier, FileRegistry from mozpack.packager.formats import FlatFormatter, JarFormatter, OmniJarFormatter from mozpack.packager.unpack import unpack_to_registry diff --git a/python/mozbuild/mozpack/test/test_path.py b/python/mozbuild/mozpack/test/test_path.py index 6c7aeb5400db..daee5df0e4bc 100644 --- a/python/mozbuild/mozpack/test/test_path.py +++ b/python/mozbuild/mozpack/test/test_path.py @@ -6,7 +6,6 @@ import os import unittest import mozunit - from mozpack.path import ( basedir, basename, diff --git a/python/mozbuild/mozpack/test/test_pkg.py b/python/mozbuild/mozpack/test/test_pkg.py index f1febbbae021..171afa63a1c1 100644 --- a/python/mozbuild/mozpack/test/test_pkg.py +++ b/python/mozbuild/mozpack/test/test_pkg.py @@ -6,9 +6,8 @@ from pathlib import Path from string import Template from unittest.mock import patch -import mozunit - import mozpack.pkg +import mozunit from mozpack.pkg import ( create_bom, create_payload, diff --git a/python/mozbuild/mozpack/test/test_unify.py b/python/mozbuild/mozpack/test/test_unify.py index 15de50dcccc1..cf2eb58160c9 100644 --- a/python/mozbuild/mozpack/test/test_unify.py +++ b/python/mozbuild/mozpack/test/test_unify.py @@ -7,14 +7,14 @@ import sys from io import StringIO import mozunit - -from mozbuild.util import ensureParentDir from mozpack.errors import AccumulatedErrors, ErrorMessage, errors from mozpack.files import FileFinder from mozpack.mozjar import JarWriter from mozpack.test.test_files import MockDest, TestWithTmpDir from mozpack.unify import UnifiedBuildFinder, UnifiedFinder +from mozbuild.util import ensureParentDir + class TestUnified(TestWithTmpDir): def create_one(self, which, path, content): diff --git a/python/mozbuild/mozpack/unify.py b/python/mozbuild/mozpack/unify.py index ca4d0017a994..3cc5c037676f 100644 --- a/python/mozbuild/mozpack/unify.py +++ b/python/mozbuild/mozpack/unify.py @@ -10,13 +10,13 @@ from collections import OrderedDict from tempfile import mkstemp import buildconfig - import mozpack.path as mozpath -from mozbuild.util import hexdump from mozpack.errors import errors from mozpack.executables import MACHO_SIGNATURES from mozpack.files import BaseFile, BaseFinder, ExecutableFile, GeneratedFile +from mozbuild.util import hexdump + # Regular expressions for unifying install.rdf FIND_TARGET_PLATFORM = re.compile( r""" diff --git a/python/mozlint/.isort.cfg b/python/mozlint/.isort.cfg new file mode 100644 index 000000000000..e8e845e642a8 --- /dev/null +++ b/python/mozlint/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozlint \ No newline at end of file diff --git a/python/mozlint/.ruff.toml b/python/mozlint/.ruff.toml deleted file mode 100644 index 11e713da73c8..000000000000 --- a/python/mozlint/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozlint"] diff --git a/python/mozperftest/.isort.cfg b/python/mozperftest/.isort.cfg new file mode 100644 index 000000000000..40c4b60057f1 --- /dev/null +++ b/python/mozperftest/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozperftest \ No newline at end of file diff --git a/python/mozperftest/.ruff.toml b/python/mozperftest/.ruff.toml deleted file mode 100644 index 10338e3dbcb0..000000000000 --- a/python/mozperftest/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozperftest"] diff --git a/python/mozrelease/.isort.cfg b/python/mozrelease/.isort.cfg new file mode 100644 index 000000000000..f5bc02c8f099 --- /dev/null +++ b/python/mozrelease/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozrelease \ No newline at end of file diff --git a/python/mozrelease/.ruff.toml b/python/mozrelease/.ruff.toml deleted file mode 100644 index 6459b1ce4afe..000000000000 --- a/python/mozrelease/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozrelease"] diff --git a/python/mozrelease/mozrelease/buglist_creator.py b/python/mozrelease/mozrelease/buglist_creator.py index 8c7b8d039193..90d9f9fb3f80 100644 --- a/python/mozrelease/mozrelease/buglist_creator.py +++ b/python/mozrelease/mozrelease/buglist_creator.py @@ -10,6 +10,7 @@ from operator import itemgetter import requests from mozilla_version.gecko import GeckoVersion + from taskcluster import Notify, optionsFromEnvironment BUGLIST_TEMPLATE = "* [Bugs since previous changeset]({url})\n" diff --git a/python/mozrelease/mozrelease/scriptworker_canary.py b/python/mozrelease/mozrelease/scriptworker_canary.py index dabdc6868d3f..92e89ed8f01c 100644 --- a/python/mozrelease/mozrelease/scriptworker_canary.py +++ b/python/mozrelease/mozrelease/scriptworker_canary.py @@ -12,11 +12,12 @@ import tempfile from contextlib import contextmanager from pathlib import Path -import taskcluster from appdirs import user_config_dir from gecko_taskgraph import GECKO from mach.base import FailedCommandError +import taskcluster + logger = logging.getLogger(__name__) diff --git a/python/mozterm/.isort.cfg b/python/mozterm/.isort.cfg new file mode 100644 index 000000000000..56fde1a106f2 --- /dev/null +++ b/python/mozterm/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozterm \ No newline at end of file diff --git a/python/mozterm/.ruff.toml b/python/mozterm/.ruff.toml deleted file mode 100644 index b3d3eaace9b7..000000000000 --- a/python/mozterm/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozterm"] diff --git a/python/mozversioncontrol/.isort.cfg b/python/mozversioncontrol/.isort.cfg new file mode 100644 index 000000000000..9fa4dfd66fed --- /dev/null +++ b/python/mozversioncontrol/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=mozversioncontrol \ No newline at end of file diff --git a/python/mozversioncontrol/.ruff.toml b/python/mozversioncontrol/.ruff.toml deleted file mode 100644 index 41f57bb0e6e8..000000000000 --- a/python/mozversioncontrol/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["mozversioncontrol"] diff --git a/taskcluster/ci/source-test/mozlint.yml b/taskcluster/ci/source-test/mozlint.yml index a6dc0651466c..c3ab520672f6 100644 --- a/taskcluster/ci/source-test/mozlint.yml +++ b/taskcluster/ci/source-test/mozlint.yml @@ -242,6 +242,20 @@ mscom-init: - '**/*.h' - 'tools/lint/mscom-init.yml' +py-flake8: + description: flake8 run over the gecko codebase + treeherder: + symbol: py(f8) + run: + mach: lint -v -l flake8 -f treeherder -f json:/builds/worker/mozlint.json * + when: + files-changed: + - '**/*.py' + - '**/.flake8' + - 'tools/lint/flake8.yml' + # moz.configure files are also Python files. + - '**/*.configure' + py-black: description: black run over the gecko codebase treeherder: @@ -258,21 +272,33 @@ py-black: - 'pyproject.toml' - 'tools/lint/black.yml' -py-ruff: - description: Run ruff over the gecko codebase +py-pylint: + description: pylint run over the gecko codebase treeherder: - symbol: py(ruff) + symbol: py(pylint) run: - mach: lint -v -l ruff -f treeherder -f json:/builds/worker/mozlint.json * + mach: lint -v -l pylint -f treeherder -f json:/builds/worker/mozlint.json * when: files-changed: - '**/*.py' + - 'tools/lint/pylint.yml' + # moz.configure files are also Python files + # However, pylint has some hard time dealing with it + +py-isort: + description: isort run over the gecko codebase + treeherder: + symbol: py(isort) + run: + mach: lint -v -l isort -f treeherder -f json:/builds/worker/mozlint.json * + when: + files-changed: + - '**/*.py' + - '**/.flake8' + - '**/.isort.cfg' + - 'tools/lint/isort.yml' + # moz.configure files are also Python files. - '**/*.configure' - - '**/.ruff.toml' - - 'pyproject.toml' - - 'tools/lint/ruff.yml' - - 'tools/lint/python/ruff.py' - - 'tools/lint/python/ruff_requirements.txt' test-manifest: description: lint test manifests diff --git a/taskcluster/gecko_taskgraph/.isort.cfg b/taskcluster/gecko_taskgraph/.isort.cfg new file mode 100644 index 000000000000..06a7ffb67193 --- /dev/null +++ b/taskcluster/gecko_taskgraph/.isort.cfg @@ -0,0 +1,3 @@ +[settings] +profile=black +known_first_party=gecko_taskgraph \ No newline at end of file diff --git a/taskcluster/gecko_taskgraph/.ruff.toml b/taskcluster/gecko_taskgraph/.ruff.toml deleted file mode 100644 index 0cd744c1cb18..000000000000 --- a/taskcluster/gecko_taskgraph/.ruff.toml +++ /dev/null @@ -1,4 +0,0 @@ -extend = "../../pyproject.toml" - -[isort] -known-first-party = ["gecko_taskgraph"] diff --git a/taskcluster/gecko_taskgraph/__init__.py b/taskcluster/gecko_taskgraph/__init__.py index 1346bf3c3330..90ad9d5bdff3 100644 --- a/taskcluster/gecko_taskgraph/__init__.py +++ b/taskcluster/gecko_taskgraph/__init__.py @@ -50,8 +50,8 @@ def register(graph_config): """ from taskgraph import generator + from gecko_taskgraph import morph # noqa: trigger morph registration from gecko_taskgraph import ( # noqa: trigger target task method registration - morph, # noqa: trigger morph registration target_tasks, ) from gecko_taskgraph.parameters import register_parameters diff --git a/taskcluster/gecko_taskgraph/transforms/task.py b/taskcluster/gecko_taskgraph/transforms/task.py index 7462d183592a..f1d3e713f123 100644 --- a/taskcluster/gecko_taskgraph/transforms/task.py +++ b/taskcluster/gecko_taskgraph/transforms/task.py @@ -17,7 +17,6 @@ import time import attr from mozbuild.util import memoize -from taskcluster.utils import fromNow from taskgraph.transforms.base import TransformSequence from taskgraph.util.keyed_by import evaluate_keyed_by from taskgraph.util.schema import ( @@ -41,6 +40,7 @@ from gecko_taskgraph.util.partners import get_partners_to_be_published from gecko_taskgraph.util.scriptworker import BALROG_ACTIONS, get_release_config from gecko_taskgraph.util.signed_artifacts import get_signed_artifacts from gecko_taskgraph.util.workertypes import get_worker_type, worker_type_implementation +from taskcluster.utils import fromNow RUN_TASK = os.path.join(GECKO, "taskcluster", "scripts", "run-task") diff --git a/taskcluster/gecko_taskgraph/util/taskcluster.py b/taskcluster/gecko_taskgraph/util/taskcluster.py index cddb01fd373d..8c863496a735 100644 --- a/taskcluster/gecko_taskgraph/util/taskcluster.py +++ b/taskcluster/gecko_taskgraph/util/taskcluster.py @@ -7,7 +7,6 @@ import logging import os import taskcluster_urls as liburls -from taskcluster import Hooks from taskgraph.util import taskcluster as tc_util from taskgraph.util.taskcluster import ( _do_request, @@ -17,6 +16,8 @@ from taskgraph.util.taskcluster import ( get_task_url, ) +from taskcluster import Hooks + logger = logging.getLogger(__name__) diff --git a/testing/condprofile/condprof/client.py b/testing/condprofile/condprof/client.py index 186e8cf4c4a0..ab901052767b 100644 --- a/testing/condprofile/condprof/client.py +++ b/testing/condprofile/condprof/client.py @@ -12,8 +12,6 @@ import tarfile import tempfile import time -from mozprofile.prefs import Preferences - from condprof import progress from condprof.changelog import Changelog from condprof.util import ( @@ -23,6 +21,7 @@ from condprof.util import ( download_file, logger, ) +from mozprofile.prefs import Preferences TC_SERVICE = "https://firefox-ci-tc.services.mozilla.com" ROOT_URL = TC_SERVICE + "/api/index" diff --git a/testing/condprofile/condprof/scenarii/full.py b/testing/condprofile/condprof/scenarii/full.py index ec93b48b46aa..9fb01f3b1f41 100644 --- a/testing/condprofile/condprof/scenarii/full.py +++ b/testing/condprofile/condprof/scenarii/full.py @@ -7,7 +7,6 @@ import os import random from arsenic.errors import UnknownArsenicError, UnknownError - from condprof.helpers import TabSwitcher, execute_async_script, is_mobile from condprof.util import get_credentials, logger diff --git a/testing/condprofile/condprof/tests/test_client.py b/testing/condprofile/condprof/tests/test_client.py index 8410133e16e6..0a6613f41562 100644 --- a/testing/condprofile/condprof/tests/test_client.py +++ b/testing/condprofile/condprof/tests/test_client.py @@ -7,10 +7,9 @@ import tempfile import unittest import responses -from mozprofile.prefs import Preferences - from condprof.client import ROOT_URL, TC_SERVICE, get_profile from condprof.util import _DEFAULT_SERVER +from mozprofile.prefs import Preferences PROFILE = re.compile(ROOT_URL + "/.*/.*tgz") PROFILE_FOR_TESTS = os.path.join(os.path.dirname(__file__), "profile") diff --git a/testing/condprofile/condprof/tests/test_runner.py b/testing/condprofile/condprof/tests/test_runner.py index e200a537e1ba..e64d9d1860a8 100644 --- a/testing/condprofile/condprof/tests/test_runner.py +++ b/testing/condprofile/condprof/tests/test_runner.py @@ -7,7 +7,6 @@ import tempfile import unittest import responses - from condprof import client from condprof.client import ROOT_URL, TC_SERVICE from condprof.main import main diff --git a/testing/condprofile/condprof/util.py b/testing/condprofile/condprof/util.py index 61bad372b1bd..83e0cc6b71e1 100644 --- a/testing/condprofile/condprof/util.py +++ b/testing/condprofile/condprof/util.py @@ -16,11 +16,10 @@ from subprocess import PIPE, Popen import mozlog import requests import yaml +from condprof import progress from requests.exceptions import ConnectionError from requests.packages.urllib3.util.retry import Retry -from condprof import progress - TASK_CLUSTER = "TASK_ID" in os.environ.keys() DOWNLOAD_TIMEOUT = 30 diff --git a/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py b/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py index 339a500f1908..c3bed1f12f51 100644 --- a/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py +++ b/testing/firefox-ui/harness/firefox_ui_harness/cli_functional.py @@ -4,10 +4,9 @@ # License, v. 2.0. If a copy of the MPL was not distributed with this # file, You can obtain one at http://mozilla.org/MPL/2.0/. -from marionette_harness.runtests import cli as mn_cli - from firefox_ui_harness.arguments import FirefoxUIArguments from firefox_ui_harness.runners import FirefoxUITestRunner +from marionette_harness.runtests import cli as mn_cli def cli(args=None): diff --git a/testing/mach_commands.py b/testing/mach_commands.py index 02ffb7a48d65..77eb428e08d6 100644 --- a/testing/mach_commands.py +++ b/testing/mach_commands.py @@ -538,7 +538,7 @@ def run_desktop_test( def run_android_test(command_context, tests, symbols_path, manifest_path, log): - import remotecppunittests + import remotecppunittests as remotecppunittests from mozlog import commandline parser = remotecppunittests.RemoteCPPUnittestOptions() diff --git a/testing/marionette/harness/marionette_harness/runner/httpd.py b/testing/marionette/harness/marionette_harness/runner/httpd.py index 8ffc85aeb0ec..98c77362b641 100755 --- a/testing/marionette/harness/marionette_harness/runner/httpd.py +++ b/testing/marionette/harness/marionette_harness/runner/httpd.py @@ -16,8 +16,9 @@ import sys import time from six.moves.urllib import parse as urlparse -from wptserve import handlers, request, server +from wptserve import handlers, request from wptserve import routes as default_routes +from wptserve import server root = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) default_doc_root = os.path.join(root, "www") diff --git a/testing/marionette/harness/marionette_harness/runtests.py b/testing/marionette/harness/marionette_harness/runtests.py index 0d86e1534d1d..00f2ce8b5c14 100644 --- a/testing/marionette/harness/marionette_harness/runtests.py +++ b/testing/marionette/harness/marionette_harness/runtests.py @@ -6,7 +6,6 @@ import sys import mozlog from marionette_driver import __version__ as driver_version - from marionette_harness import ( BaseMarionetteArguments, BaseMarionetteTestRunner, diff --git a/testing/mozbase/manifestparser/manifestparser/manifestparser.py b/testing/mozbase/manifestparser/manifestparser/manifestparser.py index c43bb150daef..c9a5df3872c7 100644 --- a/testing/mozbase/manifestparser/manifestparser/manifestparser.py +++ b/testing/mozbase/manifestparser/manifestparser/manifestparser.py @@ -13,8 +13,9 @@ import types from six import StringIO, string_types -from .filters import DEFAULT_FILTERS, enabled, filterlist +from .filters import DEFAULT_FILTERS, enabled from .filters import exists as _exists +from .filters import filterlist from .ini import read_ini __all__ = ["ManifestParser", "TestManifest", "convert"] diff --git a/testing/mozbase/mozlog/mozlog/formatters/grouping.py b/testing/mozbase/mozlog/mozlog/formatters/grouping.py index 36993b5595ef..ece1a614eaa0 100644 --- a/testing/mozbase/mozlog/mozlog/formatters/grouping.py +++ b/testing/mozbase/mozlog/mozlog/formatters/grouping.py @@ -8,7 +8,6 @@ import subprocess import sys import six - from mozlog.formatters import base DEFAULT_MOVE_UP_CODE = u"\x1b[A" diff --git a/testing/mozbase/mozlog/mozlog/handlers/base.py b/testing/mozbase/mozlog/mozlog/handlers/base.py index 59fc05cc1f89..e6bb6b6336f5 100644 --- a/testing/mozbase/mozlog/mozlog/handlers/base.py +++ b/testing/mozbase/mozlog/mozlog/handlers/base.py @@ -8,7 +8,6 @@ import locale from threading import Lock import six - from mozlog.handlers.messagehandler import MessageHandler from mozlog.structuredlog import log_levels diff --git a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py index ce51dacdeca8..529c320d771c 100644 --- a/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py +++ b/testing/mozbase/mozlog/mozlog/pytest_mozlog/plugin.py @@ -4,11 +4,10 @@ import time +import mozlog import pytest import six -import mozlog - def pytest_addoption(parser): # We can't simply use mozlog.commandline.add_logging_group(parser) here because diff --git a/testing/mozbase/mozlog/mozlog/scripts/unstable.py b/testing/mozbase/mozlog/mozlog/scripts/unstable.py index 4292aced2a4c..388fd295908c 100644 --- a/testing/mozbase/mozlog/mozlog/scripts/unstable.py +++ b/testing/mozbase/mozlog/mozlog/scripts/unstable.py @@ -7,7 +7,6 @@ import json from collections import defaultdict import six - from mozlog import reader diff --git a/testing/mozbase/mozproxy/mozproxy/backends/mitm/android.py b/testing/mozbase/mozproxy/mozproxy/backends/mitm/android.py index fe9bcd220d7f..c250d6f3e412 100644 --- a/testing/mozbase/mozproxy/mozproxy/backends/mitm/android.py +++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm/android.py @@ -9,7 +9,6 @@ import sys from subprocess import PIPE import mozinfo - from mozproxy.backends.mitm.mitm import Mitmproxy from mozproxy.utils import LOG, download_file_from_url, tooltool_download diff --git a/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py b/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py index f9c30c9b0ecb..dceb5c646457 100644 --- a/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py +++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm/desktop.py @@ -6,7 +6,6 @@ import os import sys import mozinfo - from mozproxy.backends.mitm.mitm import Mitmproxy from mozproxy.utils import LOG diff --git a/testing/mozbase/mozproxy/mozproxy/backends/mitm/mitm.py b/testing/mozbase/mozproxy/mozproxy/backends/mitm/mitm.py index 9b447f4dc28a..e5fc23b0e912 100644 --- a/testing/mozbase/mozproxy/mozproxy/backends/mitm/mitm.py +++ b/testing/mozbase/mozproxy/mozproxy/backends/mitm/mitm.py @@ -11,7 +11,6 @@ import time import mozinfo import six from mozprocess import ProcessHandler - from mozproxy.backends.base import Playback from mozproxy.recordings import RecordingFile from mozproxy.utils import ( diff --git a/testing/mozbase/mozproxy/mozproxy/utils.py b/testing/mozbase/mozproxy/mozproxy/utils.py index 49b27e70cd97..c9bf3379bbc5 100644 --- a/testing/mozbase/mozproxy/mozproxy/utils.py +++ b/testing/mozbase/mozproxy/mozproxy/utils.py @@ -26,7 +26,6 @@ except ImportError: from mozlog import get_proxy_logger from mozprocess import ProcessHandler - from mozproxy import mozbase_dir, mozharness_dir LOG = get_proxy_logger(component="mozproxy") diff --git a/testing/mozbase/mozversion/mozversion/mozversion.py b/testing/mozbase/mozversion/mozversion/mozversion.py index cca9c7e7c5d2..907023a09a0a 100644 --- a/testing/mozbase/mozversion/mozversion/mozversion.py +++ b/testing/mozbase/mozversion/mozversion/mozversion.py @@ -9,9 +9,8 @@ import sys import zipfile import mozlog -from six.moves import configparser - from mozversion import errors +from six.moves import configparser INI_DATA_MAPPING = (("application", "App"), ("platform", "Build")) diff --git a/testing/mozharness/mozharness/base/diskutils.py b/testing/mozharness/mozharness/base/diskutils.py index 757a6ffb7ab2..d61661cc3616 100644 --- a/testing/mozharness/mozharness/base/diskutils.py +++ b/testing/mozharness/mozharness/base/diskutils.py @@ -33,9 +33,8 @@ import logging import os import sys -from six import string_types - from mozharness.base.log import INFO, numeric_log_level +from six import string_types # use mozharness log log = logging.getLogger(__name__) diff --git a/testing/mozharness/mozharness/base/python.py b/testing/mozharness/mozharness/base/python.py index 338389758427..ba2514c92671 100644 --- a/testing/mozharness/mozharness/base/python.py +++ b/testing/mozharness/mozharness/base/python.py @@ -23,8 +23,6 @@ try: except ImportError: import urllib.parse as urlparse -from six import string_types - import mozharness from mozharness.base.errors import VirtualenvErrorList from mozharness.base.log import FATAL, WARNING @@ -34,6 +32,7 @@ from mozharness.base.script import ( PreScriptAction, ScriptMixin, ) +from six import string_types external_tools_path = os.path.join( os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))), diff --git a/testing/mozharness/mozharness/base/script.py b/testing/mozharness/mozharness/base/script.py index e0db58833311..5e427c792fc3 100644 --- a/testing/mozharness/mozharness/base/script.py +++ b/testing/mozharness/mozharness/base/script.py @@ -38,9 +38,6 @@ from io import BytesIO import mozinfo import six -from mozprocess import ProcessHandler -from six import binary_type - from mozharness.base.config import BaseConfig from mozharness.base.log import ( DEBUG, @@ -54,6 +51,8 @@ from mozharness.base.log import ( OutputParser, SimpleFileLogger, ) +from mozprocess import ProcessHandler +from six import binary_type try: import httplib diff --git a/testing/mozharness/mozharness/mozilla/building/buildbase.py b/testing/mozharness/mozharness/mozilla/building/buildbase.py index 54c387b8f98c..9bdc2b5b16fc 100755 --- a/testing/mozharness/mozharness/mozilla/building/buildbase.py +++ b/testing/mozharness/mozharness/mozilla/building/buildbase.py @@ -21,8 +21,6 @@ from datetime import datetime import six import yaml -from yaml import YAMLError - from mozharness.base.config import DEFAULT_CONFIG_PATH, BaseConfig, parse_config_file from mozharness.base.errors import MakefileErrorList from mozharness.base.log import ERROR, FATAL, OutputParser @@ -39,6 +37,7 @@ from mozharness.mozilla.automation import ( AutomationMixin, ) from mozharness.mozilla.secrets import SecretsMixin +from yaml import YAMLError AUTOMATION_EXIT_CODES = sorted(EXIT_STATUS_DICT.values()) diff --git a/testing/mozharness/mozharness/mozilla/testing/android.py b/testing/mozharness/mozharness/mozilla/testing/android.py index 7e1770755284..8afd8b56cca1 100644 --- a/testing/mozharness/mozharness/mozilla/testing/android.py +++ b/testing/mozharness/mozharness/mozilla/testing/android.py @@ -18,7 +18,6 @@ import time from threading import Timer import six - from mozharness.base.script import PostScriptAction, PreScriptAction from mozharness.mozilla.automation import EXIT_STATUS_DICT, TBPL_RETRY diff --git a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py index 091ff7aa1c8b..ec86cc3f1444 100644 --- a/testing/mozharness/mozharness/mozilla/testing/codecoverage.py +++ b/testing/mozharness/mozharness/mozilla/testing/codecoverage.py @@ -14,7 +14,6 @@ import uuid import zipfile import mozinfo - from mozharness.base.script import PostScriptAction, PreScriptAction from mozharness.mozilla.testing.per_test_base import SingleTestMixin diff --git a/testing/mozharness/mozharness/mozilla/testing/raptor.py b/testing/mozharness/mozharness/mozilla/testing/raptor.py index 569aee08a873..c02c4994601b 100644 --- a/testing/mozharness/mozharness/mozilla/testing/raptor.py +++ b/testing/mozharness/mozharness/mozilla/testing/raptor.py @@ -15,8 +15,6 @@ import sys import tempfile from shutil import copyfile, rmtree -from six import string_types - import mozharness from mozharness.base.errors import PythonErrorList from mozharness.base.log import CRITICAL, DEBUG, ERROR, INFO, OutputParser @@ -35,6 +33,7 @@ from mozharness.mozilla.testing.codecoverage import ( ) from mozharness.mozilla.testing.errors import HarnessErrorList, TinderBoxPrintRe from mozharness.mozilla.testing.testbase import TestingMixin, testing_config_options +from six import string_types scripts_path = os.path.abspath(os.path.dirname(os.path.dirname(mozharness.__file__))) external_tools_path = os.path.join(scripts_path, "external_tools") diff --git a/testing/mozharness/mozharness/mozilla/testing/talos.py b/testing/mozharness/mozharness/mozilla/testing/talos.py index 0dd0dcbf432a..0863668cdbc6 100755 --- a/testing/mozharness/mozharness/mozilla/testing/talos.py +++ b/testing/mozharness/mozharness/mozilla/testing/talos.py @@ -19,9 +19,8 @@ import shutil import subprocess import sys -import six - import mozharness +import six from mozharness.base.config import parse_config_file from mozharness.base.errors import PythonErrorList from mozharness.base.log import CRITICAL, DEBUG, ERROR, INFO, WARNING, OutputParser diff --git a/testing/mozharness/mozharness/mozilla/testing/testbase.py b/testing/mozharness/mozharness/mozilla/testing/testbase.py index 9254bcffeede..18943a2028d1 100755 --- a/testing/mozharness/mozharness/mozilla/testing/testbase.py +++ b/testing/mozharness/mozharness/mozilla/testing/testbase.py @@ -11,9 +11,6 @@ import os import platform import ssl -from six.moves import urllib -from six.moves.urllib.parse import ParseResult, urlparse - from mozharness.base.errors import BaseErrorList from mozharness.base.log import FATAL, WARNING from mozharness.base.python import ( @@ -31,6 +28,8 @@ from mozharness.mozilla.testing.verify_tools import ( verify_config_options, ) from mozharness.mozilla.tooltool import TooltoolMixin +from six.moves import urllib +from six.moves.urllib.parse import ParseResult, urlparse INSTALLER_SUFFIXES = ( ".apk", # Android diff --git a/testing/mozharness/mozharness/mozilla/testing/try_tools.py b/testing/mozharness/mozharness/mozilla/testing/try_tools.py index ac92ef534cc2..463bd1ad9c20 100644 --- a/testing/mozharness/mozharness/mozilla/testing/try_tools.py +++ b/testing/mozharness/mozharness/mozilla/testing/try_tools.py @@ -11,7 +11,6 @@ import re from collections import defaultdict import six - from mozharness.base.script import PostScriptAction from mozharness.base.transfer import TransferMixin diff --git a/testing/raptor/mach_commands.py b/testing/raptor/mach_commands.py index 643b11cd8e0e..54a25a75e4c9 100644 --- a/testing/raptor/mach_commands.py +++ b/testing/raptor/mach_commands.py @@ -15,8 +15,9 @@ import sys from mach.decorators import Command from mach.util import get_state_dir -from mozbuild.base import BinaryNotFoundException, MozbuildObject +from mozbuild.base import BinaryNotFoundException from mozbuild.base import MachCommandConditions as Conditions +from mozbuild.base import MozbuildObject HERE = os.path.dirname(os.path.realpath(__file__)) diff --git a/testing/talos/talos/cmanager_win32.py b/testing/talos/talos/cmanager_win32.py index 84bab8743d62..5d075efdb823 100644 --- a/testing/talos/talos/cmanager_win32.py +++ b/testing/talos/talos/cmanager_win32.py @@ -16,7 +16,6 @@ from ctypes import ( from ctypes.wintypes import DWORD, HANDLE, LONG, LPCSTR, LPCWSTR, LPSTR import six - from talos.cmanager_base import CounterManager from talos.utils import TalosError diff --git a/testing/talos/talos/config.py b/testing/talos/talos/config.py index 31ccbfd27800..7cda20ac4474 100644 --- a/testing/talos/talos/config.py +++ b/testing/talos/talos/config.py @@ -7,7 +7,6 @@ import re import sys from mozlog.commandline import setup_logging - from talos import test, utils from talos.cmdline import parse_args diff --git a/testing/talos/talos/ffsetup.py b/testing/talos/talos/ffsetup.py index c44535a677e2..4ac5ed688b94 100644 --- a/testing/talos/talos/ffsetup.py +++ b/testing/talos/talos/ffsetup.py @@ -16,7 +16,6 @@ import mozrunner import six from mozlog import get_proxy_logger from mozprofile.profile import Profile - from talos import heavy, utils from talos.gecko_profile import GeckoProfile from talos.utils import TalosError, run_in_debug_mode diff --git a/testing/talos/talos/output.py b/testing/talos/talos/output.py index b6d244a57162..b9c1b77d956d 100644 --- a/testing/talos/talos/output.py +++ b/testing/talos/talos/output.py @@ -6,7 +6,6 @@ # NOTE: we have a circular dependency with output.py when we import results import simplejson as json from mozlog import get_proxy_logger - from talos import filter, utils LOG = get_proxy_logger() diff --git a/testing/talos/talos/results.py b/testing/talos/talos/results.py index 73ebd56ed349..3ca8f5a0b62e 100755 --- a/testing/talos/talos/results.py +++ b/testing/talos/talos/results.py @@ -14,7 +14,6 @@ import os import re import six - from talos import filter, output, utils diff --git a/testing/talos/talos/run_tests.py b/testing/talos/talos/run_tests.py index d7f8c00116c8..5be7ec8ff108 100755 --- a/testing/talos/talos/run_tests.py +++ b/testing/talos/talos/run_tests.py @@ -14,14 +14,13 @@ import mozversion import six from mozgeckoprofiler import view_gecko_profile from mozlog import get_proxy_logger -from wptserve import server -from wptserve.handlers import handler - from talos import utils from talos.config import ConfigurationError, get_configs from talos.results import TalosResults from talos.ttest import TTest from talos.utils import TalosError, TalosRegression +from wptserve import server +from wptserve.handlers import handler # directory of this file here = os.path.dirname(os.path.realpath(__file__)) diff --git a/testing/talos/talos/talos_process.py b/testing/talos/talos/talos_process.py index db3a5f4b858e..5f6b539ddbf6 100644 --- a/testing/talos/talos/talos_process.py +++ b/testing/talos/talos/talos_process.py @@ -14,7 +14,6 @@ import psutil import six from mozlog import get_proxy_logger from mozprocess import ProcessHandler - from talos.utils import TalosError LOG = get_proxy_logger() diff --git a/testing/talos/talos/ttest.py b/testing/talos/talos/ttest.py index d5bdb7c9b6ab..f085f80cd9fa 100644 --- a/testing/talos/talos/ttest.py +++ b/testing/talos/talos/ttest.py @@ -23,7 +23,6 @@ import mozcrash import mozfile import six from mozlog import get_proxy_logger - from talos import results, talosconfig, utils from talos.cmanager import CounterManagement from talos.ffsetup import FFSetup diff --git a/testing/talos/talos/unittests/test_config.py b/testing/talos/talos/unittests/test_config.py index 68549f0f735f..7d62dc69f4ba 100644 --- a/testing/talos/talos/unittests/test_config.py +++ b/testing/talos/talos/unittests/test_config.py @@ -6,7 +6,6 @@ import conftest import mozunit import pytest import six - from talos.config import ( DEFAULTS, ConfigurationError, diff --git a/testing/talos/talos/unittests/test_test.py b/testing/talos/talos/unittests/test_test.py index 0f20676d251a..192fd377bb7f 100644 --- a/testing/talos/talos/unittests/test_test.py +++ b/testing/talos/talos/unittests/test_test.py @@ -1,6 +1,5 @@ import mozunit import pytest - from talos.test import Test, TsBase, register_test, test_dict, ts_paint diff --git a/testing/talos/talos/unittests/test_xtalos.py b/testing/talos/talos/unittests/test_xtalos.py index ed536d793048..458ca7dfe605 100644 --- a/testing/talos/talos/unittests/test_xtalos.py +++ b/testing/talos/talos/unittests/test_xtalos.py @@ -1,7 +1,6 @@ import re import mozunit - from talos.xtalos.etlparser import NAME_SUBSTITUTIONS diff --git a/testing/web-platform/mozilla/tests/webdriver/support/fixtures.py b/testing/web-platform/mozilla/tests/webdriver/support/fixtures.py index 3a66df07941c..f0646da31032 100644 --- a/testing/web-platform/mozilla/tests/webdriver/support/fixtures.py +++ b/testing/web-platform/mozilla/tests/webdriver/support/fixtures.py @@ -10,7 +10,6 @@ import webdriver from mozprocess import ProcessHandler from mozprofile import Profile from mozrunner import FirefoxRunner - from support.network import get_free_port diff --git a/testing/xpcshell/mach_commands.py b/testing/xpcshell/mach_commands.py index bd2c041c874f..1e16e168de13 100644 --- a/testing/xpcshell/mach_commands.py +++ b/testing/xpcshell/mach_commands.py @@ -11,8 +11,9 @@ import sys from multiprocessing import cpu_count from mach.decorators import Command -from mozbuild.base import BinaryNotFoundException, MozbuildObject +from mozbuild.base import BinaryNotFoundException from mozbuild.base import MachCommandConditions as conditions +from mozbuild.base import MozbuildObject from mozlog import structured from xpcshellcommandline import parser_desktop, parser_remote diff --git a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/fog_testcase.py b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/fog_testcase.py index c5bc54e9d232..6963aa8a0bb8 100644 --- a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/fog_testcase.py +++ b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/fog_testcase.py @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. import mozlog - from telemetry_harness.fog_ping_server import FOGPingServer from telemetry_harness.testcase import TelemetryTestCase diff --git a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runner.py b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runner.py index 37a91023cef0..21aeab2c7781 100644 --- a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runner.py +++ b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runner.py @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. from marionette_harness import BaseMarionetteTestRunner - from telemetry_harness.testcase import TelemetryTestCase SERVER_URL = "http://localhost:8000" diff --git a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runtests.py b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runtests.py index 4ecee669f179..e18905bcc5b2 100644 --- a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runtests.py +++ b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/runtests.py @@ -3,7 +3,6 @@ # file, You can obtain one at http://mozilla.org/MPL/2.0/. from marionette_harness.runtests import cli as mn_cli - from telemetry_harness.runner import TelemetryTestRunner diff --git a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py index b6f51e47b236..e77b2dc5e379 100644 --- a/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py +++ b/toolkit/components/telemetry/tests/marionette/harness/telemetry_harness/testcase.py @@ -12,7 +12,6 @@ from marionette_driver.errors import MarionetteException from marionette_driver.wait import Wait from marionette_harness import MarionetteTestCase from marionette_harness.runner.mixins.window_manager import WindowManagerMixin - from telemetry_harness.ping_server import PingServer CANARY_CLIENT_ID = "c0ffeec0-ffee-c0ff-eec0-ffeec0ffeec0" diff --git a/tools/lint/eslint/__init__.py b/tools/lint/eslint/__init__.py index e09e8b00e615..af3f5efc56fd 100644 --- a/tools/lint/eslint/__init__.py +++ b/tools/lint/eslint/__init__.py @@ -11,11 +11,10 @@ import subprocess import sys sys.path.append(os.path.join(os.path.dirname(__file__), "eslint")) +from eslint import setup_helper from mozbuild.nodeutil import find_node_executable from mozlint import result -from eslint import setup_helper - ESLINT_ERROR_MESSAGE = """ An error occurred running eslint. Please check the following error messages: diff --git a/tools/lint/file-whitespace.yml b/tools/lint/file-whitespace.yml index 7acdfe3d7992..e598a28414a0 100644 --- a/tools/lint/file-whitespace.yml +++ b/tools/lint/file-whitespace.yml @@ -3,8 +3,9 @@ file-whitespace: description: File content sanity check include: - . + - tools/lint/python/flake8_requirements.txt + - tools/lint/python/pylint_requirements.txt - tools/lint/python/black_requirements.txt - - tools/lint/python/ruff_requirements.txt - tools/lint/rst/requirements.txt - tools/lint/tox/tox_requirements.txt - tools/lint/spell/codespell_requirements.txt diff --git a/tools/lint/flake8.yml b/tools/lint/flake8.yml new file mode 100644 index 000000000000..11d31932717c --- /dev/null +++ b/tools/lint/flake8.yml @@ -0,0 +1,15 @@ +--- +flake8: + description: Python linter + # Excludes should be added to topsrcdir/.flake8. + exclude: [] + # The configure option is used by the build system + extensions: ['configure', 'py'] + support-files: + - '**/.flake8' + - 'tools/lint/python/flake8*' + # Rules that should result in warnings rather than errors. + warning-rules: [] + type: external + payload: python.flake8:lint + setup: python.flake8:setup diff --git a/tools/lint/isort.yml b/tools/lint/isort.yml new file mode 100644 index 000000000000..d15948f65ecd --- /dev/null +++ b/tools/lint/isort.yml @@ -0,0 +1,13 @@ +--- +isort: + description: Sort python imports + # Excludes should be added to topsrcdir/.flake8. + exclude: [] + extensions: ['configure', 'py'] + support-files: + - '**/.flake8' + - '**/.isort.cfg' + - 'tools/lint/python/isort*' + type: external + payload: python.isort:lint + setup: python.isort:setup diff --git a/tools/lint/perfdocs/framework_gatherers.py b/tools/lint/perfdocs/framework_gatherers.py index 656364b8d0ed..dd571db30db5 100644 --- a/tools/lint/perfdocs/framework_gatherers.py +++ b/tools/lint/perfdocs/framework_gatherers.py @@ -9,7 +9,6 @@ import re from gecko_taskgraph.util.attributes import match_run_on_projects from manifestparser import TestManifest from mozperftest.script import ScriptInfo - from perfdocs.doc_helpers import TableBuilder from perfdocs.logger import PerfDocLogger from perfdocs.utils import read_yaml diff --git a/tools/lint/perfdocs/utils.py b/tools/lint/perfdocs/utils.py index 1ba7daeb524b..3bf20d33cc48 100644 --- a/tools/lint/perfdocs/utils.py +++ b/tools/lint/perfdocs/utils.py @@ -8,7 +8,6 @@ import pathlib import yaml from mozversioncontrol import get_repository_object - from perfdocs.logger import PerfDocLogger logger = PerfDocLogger() diff --git a/tools/lint/perfdocs/verifier.py b/tools/lint/perfdocs/verifier.py index 1911210a78bb..db6f849922fd 100644 --- a/tools/lint/perfdocs/verifier.py +++ b/tools/lint/perfdocs/verifier.py @@ -6,7 +6,6 @@ import pathlib import re import jsonschema - from perfdocs.gatherer import Gatherer from perfdocs.logger import PerfDocLogger from perfdocs.utils import read_file, read_yaml @@ -551,7 +550,7 @@ class Verifier(object): valid = True break if not valid: - logger.warning( # noqa: PLE1205 + logger.warning( "Cannot find a '{documentation}' entry in the given index file", rst_path, ) diff --git a/tools/lint/pylint.yml b/tools/lint/pylint.yml new file mode 100644 index 000000000000..012629e53b6a --- /dev/null +++ b/tools/lint/pylint.yml @@ -0,0 +1,24 @@ +--- +pylint: + description: A second Python linter + include: + - configure.py + - client.py + - security/ + - accessible/ + - docs/ + - dom/base/ + - dom/websocket/ + - mozglue/ + - toolkit/components/telemetry/ + exclude: + - dom/bindings/Codegen.py + - security/manager/ssl/tests/unit/test_content_signing/pysign.py + - security/ct/tests/gtest/createSTHTestData.py + extensions: ['py'] + support-files: + - '**/.pylint' + - 'tools/lint/python/pylint*' + type: external + payload: python.pylint:lint + setup: python.pylint:setup diff --git a/tools/lint/python/black.py b/tools/lint/python/black.py index ac975e62a228..8c44a5695129 100644 --- a/tools/lint/python/black.py +++ b/tools/lint/python/black.py @@ -88,7 +88,7 @@ def parse_issues(config, output, paths, *, log): results.append(result.from_config(config, **res)) continue - log.debug(f"Unhandled line: {line}") + log.debug("Unhandled line", line) return results diff --git a/tools/lint/python/flake8.py b/tools/lint/python/flake8.py new file mode 100644 index 000000000000..88fec87822dd --- /dev/null +++ b/tools/lint/python/flake8.py @@ -0,0 +1,215 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import platform +import subprocess +import sys + +import mozfile +import mozpack.path as mozpath +from mozlint import result +from mozlint.pathutils import expand_exclusions + +here = os.path.abspath(os.path.dirname(__file__)) +FLAKE8_REQUIREMENTS_PATH = os.path.join(here, "flake8_requirements.txt") + +FLAKE8_NOT_FOUND = """ +Could not find flake8! Install flake8 and try again. + + $ pip install -U --require-hashes -r {} +""".strip().format( + FLAKE8_REQUIREMENTS_PATH +) + + +FLAKE8_INSTALL_ERROR = """ +Unable to install correct version of flake8 +Try to install it manually with: + $ pip install -U --require-hashes -r {} +""".strip().format( + FLAKE8_REQUIREMENTS_PATH +) + +LINE_OFFSETS = { + # continuation line under-indented for hanging indent + "E121": (-1, 2), + # continuation line missing indentation or outdented + "E122": (-1, 2), + # continuation line over-indented for hanging indent + "E126": (-1, 2), + # continuation line over-indented for visual indent + "E127": (-1, 2), + # continuation line under-indented for visual indent + "E128": (-1, 2), + # continuation line unaligned for hanging indend + "E131": (-1, 2), + # expected 1 blank line, found 0 + "E301": (-1, 2), + # expected 2 blank lines, found 1 + "E302": (-2, 3), +} +"""Maps a flake8 error to a lineoffset tuple. + +The offset is of the form (lineno_offset, num_lines) and is passed +to the lineoffset property of an `Issue`. +""" + + +def default_bindir(): + # We use sys.prefix to find executables as that gets modified with + # virtualenv's activate_this.py, whereas sys.executable doesn't. + if platform.system() == "Windows": + return os.path.join(sys.prefix, "Scripts") + else: + return os.path.join(sys.prefix, "bin") + + +class NothingToLint(Exception): + """Exception used to bail out of flake8's internals if all the specified + files were excluded. + """ + + +def setup(root, **lintargs): + virtualenv_manager = lintargs["virtualenv_manager"] + try: + virtualenv_manager.install_pip_requirements( + FLAKE8_REQUIREMENTS_PATH, quiet=True + ) + except subprocess.CalledProcessError: + print(FLAKE8_INSTALL_ERROR) + return 1 + + +def lint(paths, config, **lintargs): + + root = lintargs["root"] + virtualenv_bin_path = lintargs.get("virtualenv_bin_path") + config_path = os.path.join(root, ".flake8") + + results = run(paths, config, **lintargs) + fixed = 0 + + if lintargs.get("fix"): + # fix and run again to count remaining issues + fixed = len(results) + fix_cmd = [ + os.path.join(virtualenv_bin_path or default_bindir(), "autopep8"), + "--global-config", + config_path, + "--in-place", + "--recursive", + ] + + if config.get("exclude"): + fix_cmd.extend(["--exclude", ",".join(config["exclude"])]) + + subprocess.call(fix_cmd + paths) + + results = run(paths, config, **lintargs) + + fixed = fixed - len(results) + + return {"results": results, "fixed": fixed} + + +def run(paths, config, **lintargs): + from flake8 import __version__ as flake8_version + from flake8.main.application import Application + + log = lintargs["log"] + root = lintargs["root"] + config_path = os.path.join(root, ".flake8") + + # Run flake8. + app = Application() + log.debug("flake8 version={}".format(flake8_version)) + + output_file = mozfile.NamedTemporaryFile(mode="r") + flake8_cmd = [ + "--config", + config_path, + "--output-file", + output_file.name, + "--format", + '{"path":"%(path)s","lineno":%(row)s,' + '"column":%(col)s,"rule":"%(code)s","message":"%(text)s"}', + "--filename", + ",".join(["*.{}".format(e) for e in config["extensions"]]), + ] + log.debug("Command: {}".format(" ".join(flake8_cmd))) + + orig_make_file_checker_manager = app.make_file_checker_manager + + def wrap_make_file_checker_manager(self): + """Flake8 is very inefficient when it comes to applying exclusion + rules, using `expand_exclusions` to turn directories into a list of + relevant python files is an order of magnitude faster. + + Hooking into flake8 here also gives us a convenient place to merge the + `exclude` rules specified in the root .flake8 with the ones added by + tools/lint/mach_commands.py. + """ + # Ignore exclude rules if `--no-filter` was passed in. + config.setdefault("exclude", []) + if lintargs.get("use_filters", True): + config["exclude"].extend(map(mozpath.normpath, self.options.exclude)) + + # Since we use the root .flake8 file to store exclusions, we haven't + # properly filtered the paths through mozlint's `filterpaths` function + # yet. This mimics that though there could be other edge cases that are + # different. Maybe we should call `filterpaths` directly, though for + # now that doesn't appear to be necessary. + filtered = [ + p for p in paths if not any(p.startswith(e) for e in config["exclude"]) + ] + + self.options.filenames = self.options.filenames + list( + expand_exclusions(filtered, config, root) + ) + + if not self.options.filenames: + raise NothingToLint + return orig_make_file_checker_manager() + + app.make_file_checker_manager = wrap_make_file_checker_manager.__get__( + app, Application + ) + + # Make sure to run from repository root so exclusions are joined to the + # repository root and not the current working directory. + oldcwd = os.getcwd() + os.chdir(root) + try: + app.run(flake8_cmd) + except NothingToLint: + pass + finally: + os.chdir(oldcwd) + + results = [] + + WARNING_RULES = set(config.get("warning-rules", [])) + + def process_line(line): + # Escape slashes otherwise JSON conversion will not work + line = line.replace("\\", "\\\\") + try: + res = json.loads(line) + except ValueError: + print("Non JSON output from linter, will not be processed: {}".format(line)) + return + + if res.get("code") in LINE_OFFSETS: + res["lineoffset"] = LINE_OFFSETS[res["code"]] + + if res["rule"] in WARNING_RULES: + res["level"] = "warning" + + results.append(result.from_config(config, **res)) + + list(map(process_line, output_file.readlines())) + return results diff --git a/tools/lint/python/flake8_requirements.in b/tools/lint/python/flake8_requirements.in new file mode 100644 index 000000000000..0a9262b9c6e2 --- /dev/null +++ b/tools/lint/python/flake8_requirements.in @@ -0,0 +1,4 @@ +flake8==5.0.4 +zipp==0.5 +autopep8==1.7.0 +typing-extensions==3.10.0.2 diff --git a/tools/lint/python/flake8_requirements.txt b/tools/lint/python/flake8_requirements.txt new file mode 100644 index 000000000000..36879d20c839 --- /dev/null +++ b/tools/lint/python/flake8_requirements.txt @@ -0,0 +1,41 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --generate-hashes tools/lint/python/flake8_requirements.in +# +autopep8==1.7.0 \ + --hash=sha256:6f09e90a2be784317e84dc1add17ebfc7abe3924239957a37e5040e27d812087 \ + --hash=sha256:ca9b1a83e53a7fad65d731dc7a2a2d50aa48f43850407c59f6a1a306c4201142 + # via -r tools/lint/python/flake8_requirements.in +flake8==5.0.4 \ + --hash=sha256:6fbe320aad8d6b95cec8b8e47bc933004678dc63095be98528b7bdd2a9f510db \ + --hash=sha256:7a1cf6b73744f5806ab95e526f6f0d8c01c66d7bbe349562d22dfca20610b248 + # via -r tools/lint/python/flake8_requirements.in +mccabe==0.7.0 \ + --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \ + --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e + # via flake8 +pycodestyle==2.9.1 \ + --hash=sha256:2c9607871d58c76354b697b42f5d57e1ada7d261c261efac224b664affdc5785 \ + --hash=sha256:d1735fc58b418fd7c5f658d28d943854f8a849b01a5d0a1e6f3f3fdd0166804b + # via + # autopep8 + # flake8 +pyflakes==2.5.0 \ + --hash=sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2 \ + --hash=sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3 + # via flake8 +toml==0.10.2 \ + --hash=sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b \ + --hash=sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f + # via autopep8 +typing-extensions==3.10.0.2 \ + --hash=sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e \ + --hash=sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7 \ + --hash=sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34 + # via -r tools/lint/python/flake8_requirements.in +zipp==0.5 \ + --hash=sha256:46dfd547d9ccbf8bdc26ecea52818046bb28509f12bb6a0de1cd66ab06e9a9be \ + --hash=sha256:d7ac25f895fb65bff937b381353c14eb1fa23d35f40abd72a5342cd57eb57fd1 + # via -r tools/lint/python/flake8_requirements.in diff --git a/tools/lint/python/isort.py b/tools/lint/python/isort.py new file mode 100644 index 000000000000..9af0e42d10ed --- /dev/null +++ b/tools/lint/python/isort.py @@ -0,0 +1,138 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import configparser +import os +import platform +import re +import signal +import subprocess +import sys + +import mozpack.path as mozpath +from mozlint import result +from mozlint.pathutils import expand_exclusions +from mozprocess import ProcessHandler + +here = os.path.abspath(os.path.dirname(__file__)) +ISORT_REQUIREMENTS_PATH = os.path.join(here, "isort_requirements.txt") + +ISORT_INSTALL_ERROR = """ +Unable to install correct version of isort +Try to install it manually with: + $ pip install -U --require-hashes -r {} +""".strip().format( + ISORT_REQUIREMENTS_PATH +) + + +def default_bindir(): + # We use sys.prefix to find executables as that gets modified with + # virtualenv's activate_this.py, whereas sys.executable doesn't. + if platform.system() == "Windows": + return os.path.join(sys.prefix, "Scripts") + return os.path.join(sys.prefix, "bin") + + +def parse_issues(config, output, *, log): + would_sort = re.compile( + "^ERROR: (.*?) Imports are incorrectly sorted and/or formatted.$", re.I + ) + sorted = re.compile("^Fixing (.*)$", re.I) + results = [] + for line in output: + line = line.decode("utf-8") + + match = would_sort.match(line) + if match: + res = {"path": match.group(1)} + results.append(result.from_config(config, **res)) + continue + + match = sorted.match(line) + if match: + res = {"path": match.group(1), "message": "sorted"} + results.append(result.from_config(config, **res)) + continue + + log.debug("Unhandled line", line) + return results + + +class IsortProcess(ProcessHandler): + def __init__(self, config, *args, **kwargs): + self.config = config + kwargs["stream"] = False + ProcessHandler.__init__(self, *args, **kwargs) + + def run(self, *args, **kwargs): + orig = signal.signal(signal.SIGINT, signal.SIG_IGN) + ProcessHandler.run(self, *args, **kwargs) + signal.signal(signal.SIGINT, orig) + + +def run_process(config, cmd): + proc = IsortProcess(config, cmd) + proc.run() + try: + proc.wait() + except KeyboardInterrupt: + proc.kill() + + return proc.output + + +def setup(root, **lintargs): + virtualenv_manager = lintargs["virtualenv_manager"] + try: + virtualenv_manager.install_pip_requirements(ISORT_REQUIREMENTS_PATH, quiet=True) + except subprocess.CalledProcessError: + print(ISORT_INSTALL_ERROR) + return 1 + + +def lint(paths, config, **lintargs): + from isort import __version__ as isort_version + + binary = os.path.join( + lintargs.get("virtualenv_bin_path") or default_bindir(), "isort" + ) + + log = lintargs["log"] + root = lintargs["root"] + + log.debug("isort version {}".format(isort_version)) + + cmd_args = [ + binary, + "--resolve-all-configs", + "--config-root", + root, + ] + if not lintargs.get("fix"): + cmd_args.append("--check-only") + + # We merge exclusion rules from .flake8 to avoid having to repeat the same exclusions twice. + flake8_config_path = os.path.join(root, ".flake8") + flake8_config = configparser.ConfigParser() + flake8_config.read(flake8_config_path) + config["exclude"].extend( + mozpath.normpath(p.strip()) + for p in flake8_config.get("flake8", "exclude").split(",") + ) + + paths = list(expand_exclusions(paths, config, lintargs["root"])) + if len(paths) == 0: + return {"results": [], "fixed": 0} + + base_command = cmd_args + paths + log.debug("Command: {}".format(" ".join(base_command))) + + output = run_process(config, base_command) + + results = parse_issues(config, output, log=log) + + fixed = sum(1 for issue in results if issue.message == "sorted") + + return {"results": results, "fixed": fixed} diff --git a/tools/lint/python/isort_requirements.in b/tools/lint/python/isort_requirements.in new file mode 100644 index 000000000000..8eeb146b1ad2 --- /dev/null +++ b/tools/lint/python/isort_requirements.in @@ -0,0 +1 @@ +isort==5.10.1 diff --git a/tools/lint/python/isort_requirements.txt b/tools/lint/python/isort_requirements.txt new file mode 100644 index 000000000000..84df6d209345 --- /dev/null +++ b/tools/lint/python/isort_requirements.txt @@ -0,0 +1,10 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --generate-hashes --output-file=tools/lint/python/isort_requirements.txt tools/lint/python/isort_requirements.in +# +isort==5.10.1 \ + --hash=sha256:6f62d78e2f89b4500b080fe3a81690850cd254227f27f75c3a0c491a1f351ba7 \ + --hash=sha256:e8443a5e7a020e9d7f97f1d7d9cd17c88bcb3bc7e218bf9cf5095fe550be2951 + # via -r tools/lint/python/isort_requirements.in diff --git a/tools/lint/python/pylint.py b/tools/lint/python/pylint.py new file mode 100644 index 000000000000..8bb0c68b8737 --- /dev/null +++ b/tools/lint/python/pylint.py @@ -0,0 +1,133 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import json +import os +import signal +import subprocess + +from mach.site import InstallPipRequirementsException +from mozlint import result +from mozlint.pathutils import expand_exclusions +from mozprocess import ProcessHandler + +here = os.path.abspath(os.path.dirname(__file__)) +PYLINT_REQUIREMENTS_PATH = os.path.join(here, "pylint_requirements.txt") + +PYLINT_NOT_FOUND = """ +Could not find pylint! Install pylint and try again. + + $ pip install -U --require-hashes -r {} +""".strip().format( + PYLINT_REQUIREMENTS_PATH +) + + +PYLINT_INSTALL_ERROR = """ +Unable to install correct version of pylint +Try to install it manually with: + $ pip install -U --require-hashes -r {} +""".strip().format( + PYLINT_REQUIREMENTS_PATH +) + + +class PylintProcess(ProcessHandler): + def __init__(self, config, *args, **kwargs): + self.config = config + kwargs["stream"] = False + kwargs["universal_newlines"] = True + ProcessHandler.__init__(self, *args, **kwargs) + + def run(self, *args, **kwargs): + orig = signal.signal(signal.SIGINT, signal.SIG_IGN) + ProcessHandler.run(self, *args, **kwargs) + signal.signal(signal.SIGINT, orig) + + +def setup(root, **lintargs): + virtualenv_manager = lintargs["virtualenv_manager"] + try: + virtualenv_manager.install_pip_requirements( + PYLINT_REQUIREMENTS_PATH, + quiet=True, + ) + except (subprocess.CalledProcessError, InstallPipRequirementsException): + print(PYLINT_INSTALL_ERROR) + return 1 + + +def get_pylint_binary(): + return "pylint" + + +def run_process(config, cmd): + proc = PylintProcess(config, cmd) + proc.run() + try: + proc.wait() + except KeyboardInterrupt: + proc.kill() + + return proc.output + + +def parse_issues(log, config, issues_json, path): + results = [] + + try: + issues = json.loads(issues_json) + except json.decoder.JSONDecodeError: + log.debug("Could not parse the output:") + log.debug("pylint output: {}".format(issues_json)) + return [] + + for issue in issues: + res = { + "path": issue["path"], + "level": issue["type"], + "lineno": issue["line"], + "column": issue["column"], + "message": issue["message"], + "rule": issue["message-id"], + } + results.append(result.from_config(config, **res)) + return results + + +def get_pylint_version(binary): + return subprocess.check_output( + [binary, "--version"], + universal_newlines=True, + stderr=subprocess.STDOUT, + ) + + +def lint(paths, config, **lintargs): + log = lintargs["log"] + + binary = get_pylint_binary() + + log = lintargs["log"] + paths = list(expand_exclusions(paths, config, lintargs["root"])) + + cmd_args = [binary] + results = [] + + # list from https://code.visualstudio.com/docs/python/linting#_pylint + # And ignore a bit more elements + cmd_args += [ + "-fjson", + "--disable=all", + "--enable=F,E,unreachable,duplicate-key,unnecessary-semicolon,global-variable-not-assigned,unused-variable,binary-op-exception,bad-format-string,anomalous-backslash-in-string,bad-open-mode,no-else-return", # NOQA: E501 + "--disable=import-error,no-member", + ] + + base_command = cmd_args + paths + log.debug("Command: {}".format(" ".join(cmd_args))) + log.debug("pylint version: {}".format(get_pylint_version(binary))) + output = " ".join(run_process(config, base_command)) + results = parse_issues(log, config, str(output), []) + + return results diff --git a/tools/lint/python/pylint_requirements.in b/tools/lint/python/pylint_requirements.in new file mode 100644 index 000000000000..c584cdf2a6c9 --- /dev/null +++ b/tools/lint/python/pylint_requirements.in @@ -0,0 +1,5 @@ +pylint==2.15.8 +dill==0.3.4 +tomli==1.2.2 +typing-extensions==3.10.0.2 +tomlkit==0.10.1 diff --git a/tools/lint/python/pylint_requirements.txt b/tools/lint/python/pylint_requirements.txt new file mode 100644 index 000000000000..093b1ce40263 --- /dev/null +++ b/tools/lint/python/pylint_requirements.txt @@ -0,0 +1,136 @@ +# +# This file is autogenerated by pip-compile with python 3.10 +# To update, run: +# +# pip-compile --generate-hashes tools/lint/python/pylint_requirements.in +# +astroid==2.12.13 \ + --hash=sha256:10e0ad5f7b79c435179d0d0f0df69998c4eef4597534aae44910db060baeb907 \ + --hash=sha256:1493fe8bd3dfd73dc35bd53c9d5b6e49ead98497c47b2307662556a5692d29d7 + # via pylint +dill==0.3.4 \ + --hash=sha256:7e40e4a70304fd9ceab3535d36e58791d9c4a776b38ec7f7ec9afc8d3dca4d4f \ + --hash=sha256:9f9734205146b2b353ab3fec9af0070237b6ddae78452af83d2fca84d739e675 + # via + # -r tools/lint/python/pylint_requirements.in + # pylint +isort==5.11.2 \ + --hash=sha256:dd8bbc5c0990f2a095d754e50360915f73b4c26fc82733eb5bfc6b48396af4d2 \ + --hash=sha256:e486966fba83f25b8045f8dd7455b0a0d1e4de481e1d7ce4669902d9fb85e622 + # via pylint +lazy-object-proxy==1.8.0 \ + --hash=sha256:0c1c7c0433154bb7c54185714c6929acc0ba04ee1b167314a779b9025517eada \ + --hash=sha256:14010b49a2f56ec4943b6cf925f597b534ee2fe1f0738c84b3bce0c1a11ff10d \ + --hash=sha256:4e2d9f764f1befd8bdc97673261b8bb888764dfdbd7a4d8f55e4fbcabb8c3fb7 \ + --hash=sha256:4fd031589121ad46e293629b39604031d354043bb5cdf83da4e93c2d7f3389fe \ + --hash=sha256:5b51d6f3bfeb289dfd4e95de2ecd464cd51982fe6f00e2be1d0bf94864d58acd \ + --hash=sha256:6850e4aeca6d0df35bb06e05c8b934ff7c533734eb51d0ceb2d63696f1e6030c \ + --hash=sha256:6f593f26c470a379cf7f5bc6db6b5f1722353e7bf937b8d0d0b3fba911998858 \ + --hash=sha256:71d9ae8a82203511a6f60ca5a1b9f8ad201cac0fc75038b2dc5fa519589c9288 \ + --hash=sha256:7e1561626c49cb394268edd00501b289053a652ed762c58e1081224c8d881cec \ + --hash=sha256:8f6ce2118a90efa7f62dd38c7dbfffd42f468b180287b748626293bf12ed468f \ + --hash=sha256:ae032743794fba4d171b5b67310d69176287b5bf82a21f588282406a79498891 \ + --hash=sha256:afcaa24e48bb23b3be31e329deb3f1858f1f1df86aea3d70cb5c8578bfe5261c \ + --hash=sha256:b70d6e7a332eb0217e7872a73926ad4fdc14f846e85ad6749ad111084e76df25 \ + --hash=sha256:c219a00245af0f6fa4e95901ed28044544f50152840c5b6a3e7b2568db34d156 \ + --hash=sha256:ce58b2b3734c73e68f0e30e4e725264d4d6be95818ec0a0be4bb6bf9a7e79aa8 \ + --hash=sha256:d176f392dbbdaacccf15919c77f526edf11a34aece58b55ab58539807b85436f \ + --hash=sha256:e20bfa6db17a39c706d24f82df8352488d2943a3b7ce7d4c22579cb89ca8896e \ + --hash=sha256:eac3a9a5ef13b332c059772fd40b4b1c3d45a3a2b05e33a361dee48e54a4dad0 \ + --hash=sha256:eb329f8d8145379bf5dbe722182410fe8863d186e51bf034d2075eb8d85ee25b + # via astroid +mccabe==0.7.0 \ + --hash=sha256:348e0240c33b60bbdf4e523192ef919f28cb2c3d7d5c7794f74009290f236325 \ + --hash=sha256:6c2d30ab6be0e4a46919781807b4f0d834ebdd6c6e3dca0bda5a15f863427b6e + # via pylint +platformdirs==2.6.0 \ + --hash=sha256:1a89a12377800c81983db6be069ec068eee989748799b946cce2a6e80dcc54ca \ + --hash=sha256:b46ffafa316e6b83b47489d240ce17173f123a9b9c83282141c3daf26ad9ac2e + # via pylint +pylint==2.15.8 \ + --hash=sha256:ea82cd6a1e11062dc86d555d07c021b0fb65afe39becbe6fe692efd6c4a67443 \ + --hash=sha256:ec4a87c33da054ab86a6c79afa6771dc8765cb5631620053e727fcf3ef8cbed7 + # via -r tools/lint/python/pylint_requirements.in +tomli==1.2.2 \ + --hash=sha256:c6ce0015eb38820eaf32b5db832dbc26deb3dd427bd5f6556cf0acac2c214fee \ + --hash=sha256:f04066f68f5554911363063a30b108d2b5a5b1a010aa8b6132af78489fe3aade + # via + # -r tools/lint/python/pylint_requirements.in + # pylint +tomlkit==0.10.1 \ + --hash=sha256:3c517894eadef53e9072d343d37e4427b8f0b6200a70b7c9a19b2ebd1f53b951 \ + --hash=sha256:3eba517439dcb2f84cf39f4f85fd2c3398309823a3c75ac3e73003638daf7915 + # via + # -r tools/lint/python/pylint_requirements.in + # pylint +typing-extensions==3.10.0.2 \ + --hash=sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e \ + --hash=sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7 \ + --hash=sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34 + # via -r tools/lint/python/pylint_requirements.in +wrapt==1.14.1 \ + --hash=sha256:00b6d4ea20a906c0ca56d84f93065b398ab74b927a7a3dbd470f6fc503f95dc3 \ + --hash=sha256:01c205616a89d09827986bc4e859bcabd64f5a0662a7fe95e0d359424e0e071b \ + --hash=sha256:02b41b633c6261feff8ddd8d11c711df6842aba629fdd3da10249a53211a72c4 \ + --hash=sha256:07f7a7d0f388028b2df1d916e94bbb40624c59b48ecc6cbc232546706fac74c2 \ + --hash=sha256:11871514607b15cfeb87c547a49bca19fde402f32e2b1c24a632506c0a756656 \ + --hash=sha256:1b376b3f4896e7930f1f772ac4b064ac12598d1c38d04907e696cc4d794b43d3 \ + --hash=sha256:21ac0156c4b089b330b7666db40feee30a5d52634cc4560e1905d6529a3897ff \ + --hash=sha256:257fd78c513e0fb5cdbe058c27a0624c9884e735bbd131935fd49e9fe719d310 \ + --hash=sha256:2b39d38039a1fdad98c87279b48bc5dce2c0ca0d73483b12cb72aa9609278e8a \ + --hash=sha256:2cf71233a0ed05ccdabe209c606fe0bac7379fdcf687f39b944420d2a09fdb57 \ + --hash=sha256:2fe803deacd09a233e4762a1adcea5db5d31e6be577a43352936179d14d90069 \ + --hash=sha256:3232822c7d98d23895ccc443bbdf57c7412c5a65996c30442ebe6ed3df335383 \ + --hash=sha256:34aa51c45f28ba7f12accd624225e2b1e5a3a45206aa191f6f9aac931d9d56fe \ + --hash=sha256:36f582d0c6bc99d5f39cd3ac2a9062e57f3cf606ade29a0a0d6b323462f4dd87 \ + --hash=sha256:380a85cf89e0e69b7cfbe2ea9f765f004ff419f34194018a6827ac0e3edfed4d \ + --hash=sha256:40e7bc81c9e2b2734ea4bc1aceb8a8f0ceaac7c5299bc5d69e37c44d9081d43b \ + --hash=sha256:43ca3bbbe97af00f49efb06e352eae40434ca9d915906f77def219b88e85d907 \ + --hash=sha256:4fcc4649dc762cddacd193e6b55bc02edca674067f5f98166d7713b193932b7f \ + --hash=sha256:5a0f54ce2c092aaf439813735584b9537cad479575a09892b8352fea5e988dc0 \ + --hash=sha256:5a9a0d155deafd9448baff28c08e150d9b24ff010e899311ddd63c45c2445e28 \ + --hash=sha256:5b02d65b9ccf0ef6c34cba6cf5bf2aab1bb2f49c6090bafeecc9cd81ad4ea1c1 \ + --hash=sha256:60db23fa423575eeb65ea430cee741acb7c26a1365d103f7b0f6ec412b893853 \ + --hash=sha256:642c2e7a804fcf18c222e1060df25fc210b9c58db7c91416fb055897fc27e8cc \ + --hash=sha256:6a9a25751acb379b466ff6be78a315e2b439d4c94c1e99cb7266d40a537995d3 \ + --hash=sha256:6b1a564e6cb69922c7fe3a678b9f9a3c54e72b469875aa8018f18b4d1dd1adf3 \ + --hash=sha256:6d323e1554b3d22cfc03cd3243b5bb815a51f5249fdcbb86fda4bf62bab9e164 \ + --hash=sha256:6e743de5e9c3d1b7185870f480587b75b1cb604832e380d64f9504a0535912d1 \ + --hash=sha256:709fe01086a55cf79d20f741f39325018f4df051ef39fe921b1ebe780a66184c \ + --hash=sha256:7b7c050ae976e286906dd3f26009e117eb000fb2cf3533398c5ad9ccc86867b1 \ + --hash=sha256:7d2872609603cb35ca513d7404a94d6d608fc13211563571117046c9d2bcc3d7 \ + --hash=sha256:7ef58fb89674095bfc57c4069e95d7a31cfdc0939e2a579882ac7d55aadfd2a1 \ + --hash=sha256:80bb5c256f1415f747011dc3604b59bc1f91c6e7150bd7db03b19170ee06b320 \ + --hash=sha256:81b19725065dcb43df02b37e03278c011a09e49757287dca60c5aecdd5a0b8ed \ + --hash=sha256:833b58d5d0b7e5b9832869f039203389ac7cbf01765639c7309fd50ef619e0b1 \ + --hash=sha256:88bd7b6bd70a5b6803c1abf6bca012f7ed963e58c68d76ee20b9d751c74a3248 \ + --hash=sha256:8ad85f7f4e20964db4daadcab70b47ab05c7c1cf2a7c1e51087bfaa83831854c \ + --hash=sha256:8c0ce1e99116d5ab21355d8ebe53d9460366704ea38ae4d9f6933188f327b456 \ + --hash=sha256:8d649d616e5c6a678b26d15ece345354f7c2286acd6db868e65fcc5ff7c24a77 \ + --hash=sha256:903500616422a40a98a5a3c4ff4ed9d0066f3b4c951fa286018ecdf0750194ef \ + --hash=sha256:9736af4641846491aedb3c3f56b9bc5568d92b0692303b5a305301a95dfd38b1 \ + --hash=sha256:988635d122aaf2bdcef9e795435662bcd65b02f4f4c1ae37fbee7401c440b3a7 \ + --hash=sha256:9cca3c2cdadb362116235fdbd411735de4328c61425b0aa9f872fd76d02c4e86 \ + --hash=sha256:9e0fd32e0148dd5dea6af5fee42beb949098564cc23211a88d799e434255a1f4 \ + --hash=sha256:9f3e6f9e05148ff90002b884fbc2a86bd303ae847e472f44ecc06c2cd2fcdb2d \ + --hash=sha256:a85d2b46be66a71bedde836d9e41859879cc54a2a04fad1191eb50c2066f6e9d \ + --hash=sha256:a9a52172be0b5aae932bef82a79ec0a0ce87288c7d132946d645eba03f0ad8a8 \ + --hash=sha256:aa31fdcc33fef9eb2552cbcbfee7773d5a6792c137b359e82879c101e98584c5 \ + --hash=sha256:b014c23646a467558be7da3d6b9fa409b2c567d2110599b7cf9a0c5992b3b471 \ + --hash=sha256:b21bb4c09ffabfa0e85e3a6b623e19b80e7acd709b9f91452b8297ace2a8ab00 \ + --hash=sha256:b5901a312f4d14c59918c221323068fad0540e34324925c8475263841dbdfe68 \ + --hash=sha256:b9b7a708dd92306328117d8c4b62e2194d00c365f18eff11a9b53c6f923b01e3 \ + --hash=sha256:d1967f46ea8f2db647c786e78d8cc7e4313dbd1b0aca360592d8027b8508e24d \ + --hash=sha256:d52a25136894c63de15a35bc0bdc5adb4b0e173b9c0d07a2be9d3ca64a332735 \ + --hash=sha256:d77c85fedff92cf788face9bfa3ebaa364448ebb1d765302e9af11bf449ca36d \ + --hash=sha256:d79d7d5dc8a32b7093e81e97dad755127ff77bcc899e845f41bf71747af0c569 \ + --hash=sha256:dbcda74c67263139358f4d188ae5faae95c30929281bc6866d00573783c422b7 \ + --hash=sha256:ddaea91abf8b0d13443f6dac52e89051a5063c7d014710dcb4d4abb2ff811a59 \ + --hash=sha256:dee0ce50c6a2dd9056c20db781e9c1cfd33e77d2d569f5d1d9321c641bb903d5 \ + --hash=sha256:dee60e1de1898bde3b238f18340eec6148986da0455d8ba7848d50470a7a32fb \ + --hash=sha256:e2f83e18fe2f4c9e7db597e988f72712c0c3676d337d8b101f6758107c42425b \ + --hash=sha256:e3fb1677c720409d5f671e39bac6c9e0e422584e5f518bfd50aa4cbbea02433f \ + --hash=sha256:ee2b1b1769f6707a8a445162ea16dddf74285c3964f605877a20e38545c3c462 \ + --hash=sha256:ee6acae74a2b91865910eef5e7de37dc6895ad96fa23603d1d27ea69df545015 \ + --hash=sha256:ef3f72c9666bba2bab70d2a8b79f2c6d2c1a42a7f7e2b0ec83bb2f9e383950af + # via astroid diff --git a/tools/lint/python/ruff.py b/tools/lint/python/ruff.py deleted file mode 100644 index 578defe75bfe..000000000000 --- a/tools/lint/python/ruff.py +++ /dev/null @@ -1,185 +0,0 @@ -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -import json -import os -import platform -import re -import signal -import subprocess -import sys -from pathlib import Path - -import mozfile -from mozlint import result -from mozprocess.processhandler import ProcessHandler - -here = os.path.abspath(os.path.dirname(__file__)) -RUFF_REQUIREMENTS_PATH = os.path.join(here, "ruff_requirements.txt") - -RUFF_NOT_FOUND = """ -Could not find ruff! Install ruff and try again. - - $ pip install -U --require-hashes -r {} -""".strip().format( - RUFF_REQUIREMENTS_PATH -) - - -RUFF_INSTALL_ERROR = """ -Unable to install correct version of ruff! -Try to install it manually with: - $ pip install -U --require-hashes -r {} -""".strip().format( - RUFF_REQUIREMENTS_PATH -) - - -def default_bindir(): - # We use sys.prefix to find executables as that gets modified with - # virtualenv's activate_this.py, whereas sys.executable doesn't. - if platform.system() == "Windows": - return os.path.join(sys.prefix, "Scripts") - else: - return os.path.join(sys.prefix, "bin") - - -def get_ruff_version(binary): - """ - Returns found binary's version - """ - try: - output = subprocess.check_output( - [binary, "--version"], - stderr=subprocess.STDOUT, - text=True, - ) - except subprocess.CalledProcessError as e: - output = e.output - - matches = re.match(r"ruff ([0-9\.]+)", output) - if matches: - return matches[1] - print("Error: Could not parse the version '{}'".format(output)) - - -def setup(root, log, **lintargs): - virtualenv_bin_path = lintargs.get("virtualenv_bin_path") - binary = mozfile.which("ruff", path=(virtualenv_bin_path, default_bindir())) - - if binary and os.path.isfile(binary): - log.debug(f"Looking for ruff at {binary}") - version = get_ruff_version(binary) - versions = [ - line.split()[0].strip() - for line in open(RUFF_REQUIREMENTS_PATH).readlines() - if line.startswith("ruff==") - ] - if [f"ruff=={version}"] == versions: - log.debug("ruff is present with expected version {}".format(version)) - return 0 - else: - log.debug("ruff is present but unexpected version {}".format(version)) - - virtualenv_manager = lintargs["virtualenv_manager"] - try: - virtualenv_manager.install_pip_requirements(RUFF_REQUIREMENTS_PATH, quiet=True) - except subprocess.CalledProcessError: - print(RUFF_INSTALL_ERROR) - return 1 - - -class RuffProcess(ProcessHandler): - def __init__(self, config, *args, **kwargs): - self.config = config - self.stderr = [] - kwargs["stream"] = False - kwargs["universal_newlines"] = True - ProcessHandler.__init__(self, *args, **kwargs) - - def run(self, *args, **kwargs): - orig = signal.signal(signal.SIGINT, signal.SIG_IGN) - ProcessHandler.run(self, *args, **kwargs) - signal.signal(signal.SIGINT, orig) - - -def run_process(config, cmd, **kwargs): - proc = RuffProcess(config, cmd, **kwargs) - proc.run() - try: - proc.wait() - except KeyboardInterrupt: - proc.kill() - - return "\n".join(proc.output) - - -def lint(paths, config, log, **lintargs): - fixed = 0 - results = [] - - if not paths: - return {"results": results, "fixed": fixed} - - # Currently ruff only lints non `.py` files if they are explicitly passed - # in. So we need to find any non-py files manually. This can be removed - # after https://github.com/charliermarsh/ruff/issues/3410 is fixed. - exts = [e for e in config["extensions"] if e != "py"] - non_py_files = [] - for path in paths: - p = Path(path) - if not p.is_dir(): - continue - for ext in exts: - non_py_files.extend([str(f) for f in p.glob(f"**/*.{ext}")]) - - args = ["ruff", "check", "--force-exclude"] + paths + non_py_files - - if config["exclude"]: - args.append(f"--extend-exclude={','.join(config['exclude'])}") - - process_kwargs = {"processStderrLine": lambda line: log.debug(line)} - - warning_rules = set(config.get("warning-rules", [])) - if lintargs.get("fix"): - # Do a first pass with --fix-only as the json format doesn't return the - # number of fixed issues. - fix_args = args + ["--fix-only"] - - # Don't fix warnings to limit unrelated changes sneaking into patches. - fix_args.append(f"--extend-ignore={','.join(warning_rules)}") - output = run_process(config, fix_args, **process_kwargs) - matches = re.match(r"Fixed (\d+) errors?.", output) - if matches: - fixed = int(matches[1]) - - output = run_process(config, args + ["--format=json"], **process_kwargs) - if not output: - return [] - - try: - issues = json.loads(output) - except json.JSONDecodeError: - log.error(f"could not parse output: {output}") - return [] - - for issue in issues: - res = { - "path": issue["filename"], - "lineno": issue["location"]["row"], - "column": issue["location"]["column"], - "lineoffset": issue["end_location"]["row"] - issue["location"]["row"], - "message": issue["message"], - "rule": issue["code"], - "level": "error", - } - if any(issue["code"].startswith(w) for w in warning_rules): - res["level"] = "warning" - - if issue["fix"]: - res["hint"] = issue["fix"]["message"] - - results.append(result.from_config(config, **res)) - - return {"results": results, "fixed": fixed} diff --git a/tools/lint/python/ruff_requirements.in b/tools/lint/python/ruff_requirements.in deleted file mode 100644 index af3ee5763862..000000000000 --- a/tools/lint/python/ruff_requirements.in +++ /dev/null @@ -1 +0,0 @@ -ruff diff --git a/tools/lint/python/ruff_requirements.txt b/tools/lint/python/ruff_requirements.txt deleted file mode 100644 index 1c8943c26b69..000000000000 --- a/tools/lint/python/ruff_requirements.txt +++ /dev/null @@ -1,25 +0,0 @@ -# -# This file is autogenerated by pip-compile with Python 3.7 -# by the following command: -# -# pip-compile --generate-hashes ruff_requirements.in -# -ruff==0.0.254 \ - --hash=sha256:059a380c08e849b6f312479b18cc63bba2808cff749ad71555f61dd930e3c9a2 \ - --hash=sha256:09c764bc2bd80c974f7ce1f73a46092c286085355a5711126af351b9ae4bea0c \ - --hash=sha256:0deb1d7226ea9da9b18881736d2d96accfa7f328c67b7410478cc064ad1fa6aa \ - --hash=sha256:0eb66c9520151d3bd950ea43b3a088618a8e4e10a5014a72687881e6f3606312 \ - --hash=sha256:27d39d697fdd7df1f2a32c1063756ee269ad8d5345c471ee3ca450636d56e8c6 \ - --hash=sha256:2fc21d060a3197ac463596a97d9b5db2d429395938b270ded61dd60f0e57eb21 \ - --hash=sha256:688379050ae05394a6f9f9c8471587fd5dcf22149bd4304a4ede233cc4ef89a1 \ - --hash=sha256:8deba44fd563361c488dedec90dc330763ee0c01ba54e17df54ef5820079e7e0 \ - --hash=sha256:ac1429be6d8bd3db0bf5becac3a38bd56f8421447790c50599cd90fd53417ec4 \ - --hash=sha256:b3f15d5d033fd3dcb85d982d6828ddab94134686fac2c02c13a8822aa03e1321 \ - --hash=sha256:b435afc4d65591399eaf4b2af86e441a71563a2091c386cadf33eaa11064dc09 \ - --hash=sha256:c38291bda4c7b40b659e8952167f386e86ec29053ad2f733968ff1d78b4c7e15 \ - --hash=sha256:d4385cdd30153b7aa1d8f75dfd1ae30d49c918ead7de07e69b7eadf0d5538a1f \ - --hash=sha256:dd58c500d039fb381af8d861ef456c3e94fd6855c3d267d6c6718c9a9fe07be0 \ - --hash=sha256:e15742df0f9a3615fbdc1ee9a243467e97e75bf88f86d363eee1ed42cedab1ec \ - --hash=sha256:ef20bf798ffe634090ad3dc2e8aa6a055f08c448810a2f800ab716cc18b80107 \ - --hash=sha256:f70dc93bc9db15cccf2ed2a831938919e3e630993eeea6aba5c84bc274237885 - # via -r ruff_requirements.in diff --git a/tools/lint/ruff.yml b/tools/lint/ruff.yml deleted file mode 100644 index 59ae2a13500b..000000000000 --- a/tools/lint/ruff.yml +++ /dev/null @@ -1,17 +0,0 @@ ---- -ruff: - description: An extremely fast Python linter, written in Rust - # Excludes should be added to topsrcdir/pyproject.toml - exclude: [] - # The configure option is used by the build system - extensions: ["configure", "py"] - support-files: - - "**/.ruff.toml" - - "**/ruff.toml" - - "**/pyproject.toml" - - "tools/lint/python/ruff.py" - # Rules that should result in warnings rather than errors. - warning-rules: [PLR, PLW] - type: external - payload: python.ruff:lint - setup: python.ruff:setup diff --git a/tools/lint/test/files/flake8/.flake8 b/tools/lint/test/files/flake8/.flake8 new file mode 100644 index 000000000000..1933432319ea --- /dev/null +++ b/tools/lint/test/files/flake8/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 100 +exclude = + subdir/exclude, diff --git a/tools/lint/test/files/flake8/bad.py b/tools/lint/test/files/flake8/bad.py new file mode 100644 index 000000000000..9d9751c7eb97 --- /dev/null +++ b/tools/lint/test/files/flake8/bad.py @@ -0,0 +1,5 @@ +# Unused import +import distutils + +print("This is a line that is over 80 characters but under 100. It shouldn't fail.") +print("This is a line that is over not only 80, but 100 characters. It should most certainly cause a failure.") diff --git a/tools/lint/test/files/flake8/custom/.flake8 b/tools/lint/test/files/flake8/custom/.flake8 new file mode 100644 index 000000000000..cfe68833f239 --- /dev/null +++ b/tools/lint/test/files/flake8/custom/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length=110 +ignore= + F401 diff --git a/tools/lint/test/files/flake8/custom/good.py b/tools/lint/test/files/flake8/custom/good.py new file mode 100644 index 000000000000..7f9121a2ba7a --- /dev/null +++ b/tools/lint/test/files/flake8/custom/good.py @@ -0,0 +1,5 @@ +# Unused import +import distutils + +print("This is a line that is over 80 characters but under 100. It shouldn't fail.") +print("This is a line that is over not only 80, but 100 characters. It should also not cause a failure.") diff --git a/tools/lint/test/files/flake8/ext/bad.configure b/tools/lint/test/files/flake8/ext/bad.configure new file mode 100644 index 000000000000..8214ebb3c06d --- /dev/null +++ b/tools/lint/test/files/flake8/ext/bad.configure @@ -0,0 +1,2 @@ +# unused import +import os diff --git a/tools/lint/test/files/flake8/subdir/exclude/bad.py b/tools/lint/test/files/flake8/subdir/exclude/bad.py new file mode 100644 index 000000000000..9d9751c7eb97 --- /dev/null +++ b/tools/lint/test/files/flake8/subdir/exclude/bad.py @@ -0,0 +1,5 @@ +# Unused import +import distutils + +print("This is a line that is over 80 characters but under 100. It shouldn't fail.") +print("This is a line that is over not only 80, but 100 characters. It should most certainly cause a failure.") diff --git a/tools/lint/test/files/flake8/subdir/exclude/exclude_subdir/bad.py b/tools/lint/test/files/flake8/subdir/exclude/exclude_subdir/bad.py new file mode 100644 index 000000000000..9d9751c7eb97 --- /dev/null +++ b/tools/lint/test/files/flake8/subdir/exclude/exclude_subdir/bad.py @@ -0,0 +1,5 @@ +# Unused import +import distutils + +print("This is a line that is over 80 characters but under 100. It shouldn't fail.") +print("This is a line that is over not only 80, but 100 characters. It should most certainly cause a failure.") diff --git a/tools/lint/test/files/isort/.flake8 b/tools/lint/test/files/isort/.flake8 new file mode 100644 index 000000000000..1933432319ea --- /dev/null +++ b/tools/lint/test/files/isort/.flake8 @@ -0,0 +1,4 @@ +[flake8] +max-line-length = 100 +exclude = + subdir/exclude, diff --git a/tools/lint/test/files/isort/bad.py b/tools/lint/test/files/isort/bad.py new file mode 100644 index 000000000000..18719173734e --- /dev/null +++ b/tools/lint/test/files/isort/bad.py @@ -0,0 +1,8 @@ +import prova +import collections + + +def foobar(): + c = collections.Counter() + prova.ciao(c) + diff --git a/tools/lint/test/files/isort/subdir/exclude/bad.py b/tools/lint/test/files/isort/subdir/exclude/bad.py new file mode 100644 index 000000000000..58f5363ff000 --- /dev/null +++ b/tools/lint/test/files/isort/subdir/exclude/bad.py @@ -0,0 +1,9 @@ +import collections + +import prova + + +def foobar(): + c = collections.Counter() + prova.ciao(c) + diff --git a/tools/lint/test/files/pylint/bad.py b/tools/lint/test/files/pylint/bad.py new file mode 100644 index 000000000000..61b69a49cf11 --- /dev/null +++ b/tools/lint/test/files/pylint/bad.py @@ -0,0 +1,5 @@ +def foo(): + useless_var = 1 + useless_var = true + return "true" + print("unreachable") \ No newline at end of file diff --git a/tools/lint/test/files/pylint/good.py b/tools/lint/test/files/pylint/good.py new file mode 100644 index 000000000000..c867dc66ec60 --- /dev/null +++ b/tools/lint/test/files/pylint/good.py @@ -0,0 +1,3 @@ +def foo(): + a = 1 + 1 + return a diff --git a/tools/lint/test/files/ruff/bad.py b/tools/lint/test/files/ruff/bad.py deleted file mode 100644 index 0015d7e7f9d6..000000000000 --- a/tools/lint/test/files/ruff/bad.py +++ /dev/null @@ -1,4 +0,0 @@ -import distutils - -if not "foo" in "foobar": - print("oh no!") diff --git a/tools/lint/test/files/ruff/ruff.toml b/tools/lint/test/files/ruff/ruff.toml deleted file mode 100644 index 34f5ca74a453..000000000000 --- a/tools/lint/test/files/ruff/ruff.toml +++ /dev/null @@ -1 +0,0 @@ -# Empty config to force ruff to ignore the global one. diff --git a/tools/lint/test/python.ini b/tools/lint/test/python.ini index 06afff106f94..c09db40dccf4 100644 --- a/tools/lint/test/python.ini +++ b/tools/lint/test/python.ini @@ -13,6 +13,8 @@ skip-if = os == "win" # busts the tree for subsequent tasks on the same worker [test_file_perm.py] skip-if = os == "win" [test_file_whitespace.py] +[test_flake8.py] +requirements = tools/lint/python/flake8_requirements.txt [test_fluent_lint.py] [test_lintpref.py] [test_manifest_alpha.py] @@ -20,11 +22,13 @@ skip-if = os == "win" [test_perfdocs_generation.py] [test_updatebot.py] [test_perfdocs_helpers.py] +[test_pylint.py] +requirements = tools/lint/python/pylint_requirements.txt [test_rst.py] requirements = tools/lint/rst/requirements.txt -[test_ruff.py] -requirements = tools/lint/python/ruff_requirements.txt [test_rustfmt.py] [test_shellcheck.py] [test_trojan_source.py] [test_yaml.py] +[test_isort.py] +requirements = tools/lint/python/isort_requirements.txt diff --git a/tools/lint/test/test_flake8.py b/tools/lint/test/test_flake8.py new file mode 100644 index 000000000000..d44e3828edd2 --- /dev/null +++ b/tools/lint/test/test_flake8.py @@ -0,0 +1,117 @@ +import os + +import mozunit + +LINTER = "flake8" +fixed = 0 + + +def test_lint_single_file(lint, paths): + results = lint(paths("bad.py")) + assert len(results) == 2 + assert results[0].rule == "F401" + assert results[0].level == "error" + assert results[1].rule == "E501" + assert results[1].level == "error" + assert results[1].lineno == 5 + + # run lint again to make sure the previous results aren't counted twice + results = lint(paths("bad.py")) + assert len(results) == 2 + + +def test_lint_custom_config_ignored(lint, paths): + results = lint(paths("custom")) + assert len(results) == 2 + + results = lint(paths("custom/good.py")) + assert len(results) == 2 + + +def test_lint_fix(lint, create_temp_file): + global fixed + contents = """ +import distutils + +def foobar(): + pass +""".lstrip() + + path = create_temp_file(contents, name="bad.py") + results = lint([path]) + assert len(results) == 2 + + # Make sure the missing blank line is fixed, but the unused import isn't. + results = lint([path], fix=True) + assert len(results) == 1 + assert fixed == 1 + + fixed = 0 + + # Also test with a directory + path = os.path.dirname(create_temp_file(contents, name="bad2.py")) + results = lint([path], fix=True) + # There should now be two files with 2 combined errors + assert len(results) == 2 + assert fixed == 1 + assert all(r.rule != "E501" for r in results) + + +def test_lint_fix_uses_config(lint, create_temp_file): + contents = """ +foo = ['A list of strings', 'that go over 80 characters', 'to test if autopep8 fixes it'] +""".lstrip() + + path = create_temp_file(contents, name="line_length.py") + lint([path], fix=True) + + # Make sure autopep8 reads the global config under lintargs['root']. If it + # didn't, then the line-length over 80 would get fixed. + with open(path, "r") as fh: + assert fh.read() == contents + + +def test_lint_excluded_file(lint, paths, config): + # First file is globally excluded, second one is from .flake8 config. + files = paths("bad.py", "subdir/exclude/bad.py", "subdir/exclude/exclude_subdir") + config["exclude"] = paths("bad.py") + results = lint(files, config) + print(results) + assert len(results) == 0 + + # Make sure excludes also apply when running from a different cwd. + cwd = paths("subdir")[0] + os.chdir(cwd) + + results = lint(paths("subdir/exclude")) + print(results) + assert len(results) == 0 + + +def test_lint_excluded_file_with_glob(lint, paths, config): + config["exclude"] = paths("ext/*.configure") + + files = paths("ext") + results = lint(files, config) + print(results) + assert len(results) == 0 + + files = paths("ext/bad.configure") + results = lint(files, config) + print(results) + assert len(results) == 0 + + +def test_lint_excluded_file_with_no_filter(lint, paths, config): + results = lint(paths("subdir/exclude"), use_filters=False) + print(results) + assert len(results) == 4 + + +def test_lint_uses_custom_extensions(lint, paths): + assert len(lint(paths("ext"))) == 1 + assert len(lint(paths("ext/bad.configure"))) == 1 + + +if __name__ == "__main__": + mozunit.main() diff --git a/tools/lint/test/test_isort.py b/tools/lint/test/test_isort.py new file mode 100644 index 000000000000..180bfbebd0d5 --- /dev/null +++ b/tools/lint/test/test_isort.py @@ -0,0 +1,114 @@ +# -*- coding: utf-8 -*- + +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +import os + +import mozunit + +LINTER = "isort" +fixed = 0 + + +def test_lint_fix(lint, create_temp_file): + contents = """ +import prova +import collections + + +def foobar(): + c = collections.Counter() + prova.ciao(c) +""".lstrip() + + path = create_temp_file(contents, name="bad.py") + results = lint([path]) + assert len(results) == 1 + assert results[0].level == "error" + + lint([path], fix=True) + assert fixed == 1 + + +def test_lint_excluded_file(lint, paths, config): + # Second file is excluded from .flake8 config. + files = paths("bad.py", "subdir/exclude/bad.py", "subdir/exclude/exclude_subdir") + results = lint(files, config) + assert len(results) == 1 + + # First file is globally excluded, second one is from .flake8 config. + files = paths("bad.py", "subdir/exclude/bad.py", "subdir/exclude/exclude_subdir") + config["exclude"] = paths("bad.py") + results = lint(files, config) + assert len(results) == 0 + + # Make sure excludes also apply when running from a different cwd. + cwd = paths("subdir")[0] + os.chdir(cwd) + + results = lint(paths("subdir/exclude")) + assert len(results) == 0 + + +def test_lint_uses_all_configs(lint, paths, tmpdir): + myself = tmpdir.join("myself") + myself.mkdir() + + flake8_path = tmpdir.join(".flake8") + flake8_path.write( + """ +[flake8] +exclude = +""".lstrip() + ) + + py_path = myself.join("good.py") + py_path.write( + """ +import os + +from myself import something_else +from third_party import something + + +def ciao(): + pass +""".lstrip() + ) + + results = lint([py_path.strpath]) + assert len(results) == 0 + + isort_cfg_path = myself.join(".isort.cfg") + isort_cfg_path.write( + """ +[settings] +known_first_party = myself +""".lstrip() + ) + + results = lint([py_path.strpath], root=tmpdir.strpath) + assert len(results) == 1 + + py_path.write( + """ +import os + +from third_party import something + +from myself import something_else + + +def ciao(): + pass +""".lstrip() + ) + + results = lint([py_path.strpath], root=tmpdir.strpath) + assert len(results) == 0 + + +if __name__ == "__main__": + mozunit.main() diff --git a/tools/lint/test/test_pylint.py b/tools/lint/test/test_pylint.py new file mode 100644 index 000000000000..6ee2217089a4 --- /dev/null +++ b/tools/lint/test/test_pylint.py @@ -0,0 +1,24 @@ +import mozunit + +LINTER = "pylint" + + +def test_lint_single_file(lint, paths): + results = lint(paths("bad.py")) + assert len(results) == 3 + assert results[1].rule == "E0602" + assert results[2].rule == "W0101" + assert results[2].lineno == 5 + + # run lint again to make sure the previous results aren't counted twice + results = lint(paths("bad.py")) + assert len(results) == 3 + + +def test_lint_single_file_good(lint, paths): + results = lint(paths("good.py")) + assert len(results) == 0 + + +if __name__ == "__main__": + mozunit.main() diff --git a/tools/lint/test/test_ruff.py b/tools/lint/test/test_ruff.py deleted file mode 100644 index fbb483780e54..000000000000 --- a/tools/lint/test/test_ruff.py +++ /dev/null @@ -1,39 +0,0 @@ -# -*- coding: utf-8 -*- - -# This Source Code Form is subject to the terms of the Mozilla Public -# License, v. 2.0. If a copy of the MPL was not distributed with this -# file, You can obtain one at http://mozilla.org/MPL/2.0/. - -from pprint import pprint -from textwrap import dedent - -import mozunit - -LINTER = "ruff" -fixed = 0 - - -def test_lint_fix(lint, create_temp_file): - contents = dedent( - """ - import distutils - print("hello!") - """ - ) - - path = create_temp_file(contents, "bad.py") - lint([path], fix=True) - assert fixed == 1 - - -def test_lint_ruff(lint, paths): - results = lint(paths()) - pprint(results, indent=2) - assert len(results) == 2 - assert results[0].level == "error" - assert results[0].relpath == "bad.py" - assert "`distutils` imported but unused" in results[0].message - - -if __name__ == "__main__": - mozunit.main() diff --git a/tools/moztreedocs/mach_commands.py b/tools/moztreedocs/mach_commands.py index d2aee6edcfb0..487733c97036 100644 --- a/tools/moztreedocs/mach_commands.py +++ b/tools/moztreedocs/mach_commands.py @@ -150,7 +150,6 @@ def build_docs( import webbrowser from livereload import Server - from moztreedocs.package import create_tarball unique_id = "%s/%s" % (project(), str(uuid.uuid1())) diff --git a/tools/tryselect/selectors/chooser/__init__.py b/tools/tryselect/selectors/chooser/__init__.py index b71cf801ea39..51263a184545 100644 --- a/tools/tryselect/selectors/chooser/__init__.py +++ b/tools/tryselect/selectors/chooser/__init__.py @@ -7,7 +7,6 @@ import webbrowser from threading import Timer from gecko_taskgraph.target_tasks import filter_by_uncommon_try_tasks - from tryselect.cli import BaseTryParser from tryselect.push import ( check_working_directory, diff --git a/tools/tryselect/selectors/compare.py b/tools/tryselect/selectors/compare.py index 0ca20f59b241..a6e77ad61b23 100644 --- a/tools/tryselect/selectors/compare.py +++ b/tools/tryselect/selectors/compare.py @@ -6,7 +6,6 @@ import os from mozbuild.base import MozbuildObject from mozversioncontrol import get_repository_object - from tryselect.cli import BaseTryParser from .again import run as again_run diff --git a/xpcom/idl-parser/xpidl/runtests.py b/xpcom/idl-parser/xpidl/runtests.py index 2dd269dfd980..f209b5483a15 100755 --- a/xpcom/idl-parser/xpidl/runtests.py +++ b/xpcom/idl-parser/xpidl/runtests.py @@ -15,7 +15,6 @@ sys.path.pop(0) import unittest import mozunit - from xpidl import header, xpidl