diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 401893365..3defab809 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -5,7 +5,7 @@ ci: repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: "v4.4.0" + rev: "v4.5.0" hooks: - id: check-added-large-files - id: check-case-conflict @@ -20,33 +20,34 @@ repos: - id: trailing-whitespace - repo: https://github.com/psf/black-pre-commit-mirror - rev: "23.7.0" + rev: "23.10.1" hooks: - id: black - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.0.275" + rev: "v0.1.3" hooks: - id: ruff args: ["--fix", "--show-fixes"] - repo: https://github.com/pre-commit/mirrors-mypy - rev: "v1.3.0" + rev: "v1.6.1" hooks: - id: mypy files: plumbum args: [] - additional_dependencies: [typed-ast, types-paramiko, types-setuptools] + additional_dependencies: [typed-ast, types-paramiko, types-setuptools, pytest] - repo: https://github.com/abravalheri/validate-pyproject - rev: "v0.13" + rev: "v0.15" hooks: - id: validate-pyproject - repo: https://github.com/codespell-project/codespell - rev: "v2.2.4" + rev: "v2.2.6" hooks: - id: codespell + args: ["-w"] - repo: https://github.com/pre-commit/pygrep-hooks rev: "v1.10.0" diff --git a/conda.recipe/README.mkd b/conda.recipe/README.mkd index 3613d5964..73ee4263a 100644 --- a/conda.recipe/README.mkd +++ b/conda.recipe/README.mkd @@ -1,7 +1,7 @@ # Building instructions -Change to the `conda.recipies` directory. Run +Change to the `conda.recipes` directory. Run ```bash $ conda install conda-build ``` diff --git a/experiments/parallel.py b/experiments/parallel.py index 9954efd92..1814d5af6 100644 --- a/experiments/parallel.py +++ b/experiments/parallel.py @@ -166,7 +166,7 @@ def __exit__(self, t, v, tb): self.close() def __del__(self): - try: # noqa: 167 + try: # noqa: SIM105 self.close() except Exception: pass diff --git a/noxfile.py b/noxfile.py index 9c3928374..e83d0409a 100644 --- a/noxfile.py +++ b/noxfile.py @@ -22,7 +22,7 @@ def pylint(session): Run pylint. """ - session.install(".", "paramiko", "ipython", "pylint~=2.17.4") + session.install(".", "paramiko", "ipython", "pylint~=3.0.2") session.run("pylint", "plumbum", *session.posargs) diff --git a/plumbum/__init__.py b/plumbum/__init__.py index f7bda3f8d..d8df78d87 100644 --- a/plumbum/__init__.py +++ b/plumbum/__init__.py @@ -89,7 +89,7 @@ # =================================================================================================== -if sys.version_info < (3, 7): +if sys.version_info < (3, 7): # noqa: UP036 from types import ModuleType from typing import List diff --git a/plumbum/_testtools.py b/plumbum/_testtools.py index f1076b739..a7c4bef1d 100644 --- a/plumbum/_testtools.py +++ b/plumbum/_testtools.py @@ -2,7 +2,7 @@ import platform import sys -import pytest # type: ignore[import] +import pytest skip_without_chown = pytest.mark.skipif( not hasattr(os, "chown"), reason="os.chown not supported" diff --git a/plumbum/commands/processes.py b/plumbum/commands/processes.py index 2ccb49863..802ede4d2 100644 --- a/plumbum/commands/processes.py +++ b/plumbum/commands/processes.py @@ -114,7 +114,7 @@ class ProcessExecutionError(OSError): def __init__(self, argv, retcode, stdout, stderr, message=None, *, host=None): # we can't use 'super' here since OSError only keeps the first 2 args, - # which leads to failuring in loading this object from a pickle.dumps. + # which leads to failing in loading this object from a pickle.dumps. # pylint: disable-next=non-parent-init-called Exception.__init__(self, argv, retcode, stdout, stderr) @@ -341,7 +341,7 @@ def iter_lines( :param buffer_size: Maximum number of lines to keep in the stdout/stderr buffers, in case of a ProcessExecutionError. Default is ``None``, which defaults to DEFAULT_BUFFER_SIZE (which is infinite by default). - ``0`` will disable bufferring completely. + ``0`` will disable buffering completely. :param mode: Controls what the generator yields. Defaults to DEFAULT_ITER_LINES_MODE (which is BY_POSITION by default) - BY_POSITION (default): yields ``(out, err)`` line tuples, where either item may be ``None`` diff --git a/plumbum/machines/local.py b/plumbum/machines/local.py index 90098635b..436778579 100644 --- a/plumbum/machines/local.py +++ b/plumbum/machines/local.py @@ -259,8 +259,10 @@ def _popen( kwargs["start_new_session"] = True if IS_WIN32 and "startupinfo" not in kwargs and stdin not in (sys.stdin, None): + # pylint: disable-next=used-before-assignment subsystem = get_pe_subsystem(str(executable)) + # pylint: disable-next=used-before-assignment if subsystem == IMAGE_SUBSYSTEM_WINDOWS_CUI: # don't open a new console sui = subprocess.STARTUPINFO() diff --git a/plumbum/path/base.py b/plumbum/path/base.py index 1ae67986c..29f13ac08 100644 --- a/plumbum/path/base.py +++ b/plumbum/path/base.py @@ -41,7 +41,7 @@ def __truediv__(self: _PathImpl, other: typing.Any) -> _PathImpl: return self.join(other) def __getitem__(self, key): - if type(key) == str or isinstance(key, Path): + if type(key) == str or isinstance(key, Path): # noqa: E721 return self / key return str(self)[key] @@ -419,10 +419,8 @@ def _glob(pattern, fn): if isinstance(pattern, str): return fn(pattern) - results = [] - for single_pattern in pattern: - results.extend(fn(single_pattern)) - return sorted(list(set(results))) + results = {value for single_pattern in pattern for value in fn(single_pattern)} + return sorted(results) def resolve(self, strict=False): # noqa: ARG002 """Added to allow pathlib like syntax. Does nothing since diff --git a/plumbum/path/local.py b/plumbum/path/local.py index 068aa0eac..cea125a47 100644 --- a/plumbum/path/local.py +++ b/plumbum/path/local.py @@ -203,7 +203,7 @@ def mkdir(self, mode=0o777, parents=True, exist_ok=True): raise def open(self, mode="r", encoding=None): - return open( + return open( # noqa: SIM115 str(self), mode, encoding=encoding, diff --git a/pyproject.toml b/pyproject.toml index 4921a7ab1..0c45d2e36 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -80,7 +80,7 @@ build.hooks.vcs.version-file = "plumbum/version.py" [tool.mypy] files = ["plumbum"] -python_version = "3.6" +python_version = "3.7" warn_unused_configs = true warn_unused_ignores = true show_error_codes = true @@ -105,7 +105,7 @@ ignore_missing_imports = true [tool.pytest.ini_options] minversion = "6.0" -addopts = ["-ra", "--cov-config=setup.cfg", "--strict-markers", "--strict-config"] +addopts = ["-ra", "--showlocals", "--cov-config=setup.cfg", "--strict-markers", "--strict-config"] norecursedirs = ["examples", "experiments"] filterwarnings = [ "always" @@ -167,9 +167,12 @@ messages_control.disable = [ ] [tool.ruff] -select = [ - "E", "F", "W", # flake8 - "B", "B904", # flake8-bugbear +target-version = "py37" +exclude = ["docs/conf.py"] + +[tool.ruff.lint] +extend-select = [ + "B", # flake8-bugbear "I", # isort "ARG", # flake8-unused-arguments "C4", # flake8-comprehensions @@ -185,21 +188,17 @@ select = [ "T20", # flake8-print "UP", # pyupgrade "YTT", # flake8-2020 - ] -extend-ignore = [ +ignore = [ "E501", "PLR", "PT004", "PT011", # TODO: add match parameter "RUF012", # ClassVar required if mutable ] -target-version = "py37" -exclude = ["docs/conf.py"] -mccabe.max-complexity = 50 flake8-unused-arguments.ignore-variadic-names = true -[tool.ruff.per-file-ignores] +[tool.ruff.lint.per-file-ignores] "examples/*" = ["T20"] "experiments/*" = ["T20"] "tests/*" = ["T20"] diff --git a/tests/test_local.py b/tests/test_local.py index c17981b3f..889624ab9 100644 --- a/tests/test_local.py +++ b/tests/test_local.py @@ -902,16 +902,14 @@ def test_atomic_counter(self): num_of_procs = 20 num_of_increments = 20 - code = """from plumbum.fs.atomic import AtomicCounterFile + code = f"""from plumbum.fs.atomic import AtomicCounterFile import time time.sleep(0.2) afc = AtomicCounterFile.open("counter") -for _ in range({}): +for _ in range({num_of_increments}): print(afc.next()) time.sleep(0.1) -""".format( - num_of_increments, - ) +""" procs = [] for _ in range(num_of_procs): diff --git a/tests/test_remote.py b/tests/test_remote.py index 7d4965886..913dc9a16 100644 --- a/tests/test_remote.py +++ b/tests/test_remote.py @@ -528,14 +528,12 @@ def test_reverse_tunnel(self, dynamic_dport): assert_is_port(tun.dport) assert tun.reverse - remote_send_af_inet = """import socket + remote_send_af_inet = f"""import socket s = socket.socket() -s.connect(("localhost", {})) -s.send("{}".encode("ascii")) +s.connect(("localhost", {tun.dport})) +s.send("{message}".encode("ascii")) s.close() -""".format( - tun.dport, message - ) +""" (rem.python["-u"] << remote_send_af_inet).popen() tunnel_server.join(timeout=1) assert queue.get() == message