From da91e3a3416e5fcf342a0467b4af49f1722858e7 Mon Sep 17 00:00:00 2001 From: Ruslan Sayfutdinov Date: Fri, 13 Sep 2024 23:11:00 +0200 Subject: [PATCH] Replace flake8 and isort with ruff lint --- .github/actions/install-deps/action.yml | 3 +- .pre-commit-config.yaml | 11 +- glocaltokens/client.py | 13 +- glocaltokens/scanner.py | 6 +- glocaltokens/utils/logs.py | 3 +- pyproject.toml | 158 ++++++++++++++++++++---- setup.cfg | 17 --- tests/assertions.py | 7 +- tests/factory/providers.py | 3 +- tests/test_scanner.py | 4 +- uv.lock | 111 +---------------- 11 files changed, 149 insertions(+), 187 deletions(-) delete mode 100644 setup.cfg diff --git a/.github/actions/install-deps/action.yml b/.github/actions/install-deps/action.yml index fd10b91..3bd1f2a 100644 --- a/.github/actions/install-deps/action.yml +++ b/.github/actions/install-deps/action.yml @@ -27,5 +27,4 @@ runs: - name: Install dependencies with uv shell: bash - run: | - uv sync + run: uv sync diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0d3e118..f271524 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -16,9 +16,9 @@ repos: language: system types: [python] require_serial: true - - id: isort - name: isort - entry: uv run isort + - id: ruff + name: ruff check + entry: uv run ruff check --fix language: system types: [python] require_serial: true @@ -28,11 +28,6 @@ repos: language: system types: [python] require_serial: true - - id: flake8 - name: flake8 - entry: uv run flake8 - language: system - types: [python] - id: pylint name: pylint entry: uv run pylint diff --git a/glocaltokens/client.py b/glocaltokens/client.py index 3150974..9ccff87 100644 --- a/glocaltokens/client.py +++ b/glocaltokens/client.py @@ -48,9 +48,7 @@ def __init__( network_device: NetworkDevice | None = None, hardware: str | None = None, ): - """ - Initializes a Device. - """ + """Initializes a Device.""" log_prefix = f"[Device - {device_name}(id={device_id})]" LOGGER.debug("%s Initializing new Device instance", log_prefix) self.device_id = device_id @@ -136,8 +134,7 @@ def __init__( android_id: str | None = None, verbose: bool = False, ): - """ - Initialize an GLocalAuthenticationTokens instance with google account + """Initialize an GLocalAuthenticationTokens instance with google account credentials :params username: google account username; @@ -360,8 +357,7 @@ def get_google_devices( force_homegraph_reload: bool = False, discovery_timeout: int = DISCOVERY_TIMEOUT, ) -> list[Device]: - """ - Returns a list of google devices with their local authentication tokens, + """Returns a list of google devices with their local authentication tokens, and IP and ports if set in models_list. models_list: The list of accepted model names. @@ -492,8 +488,7 @@ def get_google_devices_json( zeroconf_instance: Zeroconf | None = None, force_homegraph_reload: bool = False, ) -> str: - """ - Returns a json list of google devices with their local authentication tokens, + """Returns a json list of google devices with their local authentication tokens, and IP and ports if set in models_list. models_list: The list of accepted model names. diff --git a/glocaltokens/scanner.py b/glocaltokens/scanner.py index 8240121..eb4bfe0 100644 --- a/glocaltokens/scanner.py +++ b/glocaltokens/scanner.py @@ -2,9 +2,10 @@ from __future__ import annotations +from collections.abc import Callable import logging from threading import Event -from typing import Callable, NamedTuple +from typing import NamedTuple from zeroconf import ServiceBrowser, ServiceInfo, ServiceListener, Zeroconf @@ -25,8 +26,7 @@ class NetworkDevice(NamedTuple): class CastListener(ServiceListener): - """ - Zeroconf Cast Services collection. + """Zeroconf Cast Services collection. Credit (pychromecast): https://github.com/home-assistant-libs/pychromecast/ """ diff --git a/glocaltokens/utils/logs.py b/glocaltokens/utils/logs.py index 8a959cd..419e5c6 100644 --- a/glocaltokens/utils/logs.py +++ b/glocaltokens/utils/logs.py @@ -6,8 +6,7 @@ def censor( text: str | None, hide_length: bool = False, hide_first_letter: bool = False ) -> str: - """ - Hide sensitive information. + """Hide sensitive information. text: The text to censure. """ diff --git a/pyproject.toml b/pyproject.toml index 2af58b3..fb59d97 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,14 +23,14 @@ repository = "https://github.com/leikoilja/glocaltokens" requires-python = ">=3.9" dynamic = ["version"] dependencies = [ - "ghome-foyer-api >= 1.0.0", - "gpsoauth >= 1.1.1", - "simplejson >= 3.19.3", + "ghome-foyer-api>=1.0.0", + "gpsoauth>=1.1.1", + "simplejson>=3.19.3", # Note, we want to keep versions of grpcio, requests and zeroconf similar to Home Assistant # https://github.com/home-assistant/core/blob/2024.9.0/homeassistant/package_constraints.txt - "grpcio >= 1.59.0", - "requests >= 2.32.3", - "zeroconf >= 0.133.0", + "grpcio>=1.59.0", + "requests>=2.32.3", + "zeroconf>=0.133.0", ] [project.urls] @@ -39,22 +39,16 @@ dependencies = [ [tool.uv] dev-dependencies = [ - "codespell >= 2.3.0", - "faker >= 20.1.0", - "flake8 >= 6.1.0", - "flake8-bugbear >= 23.12.2", - "flake8-comprehensions >= 3.15.0", - "flake8-simplify >= 0.21.0", - "flake8-use-fstring >= 1.4", - "grpc-stubs >= 1.53.0.5", - "isort >= 5.13.2", - "mock >= 5.1.0", - "mypy >= 1.11.0", - "pre-commit >= 3.8.0", - "pylint >= 3.2.7", - "pytest >= 7.4.4", + "codespell>=2.3.0", + "faker>=20.1.0", + "grpc-stubs>=1.53.0.5", + "mock>=5.1.0", + "mypy>=1.11.0", + "pre-commit>=3.8.0", + "pylint>=3.2.7", + "pytest>=7.4.4", "ruff>=0.6.4", - "types-protobuf >= 4.25.0.20240417", + "types-protobuf>=4.25.0.20240417", ] [build-system] @@ -68,6 +62,117 @@ source = "vcs" required-version = ">=0.6.0" target-version = "py39" +[tool.ruff.lint] +select = [ + "A001", # Variable {name} is shadowing a Python builtin + "ASYNC", # flake8-async + "B", # flake8-bugbear + "BLE", + "C", # complexity, including flake8-comprehensions + "COM818", # Trailing comma on bare tuple prohibited + "D", # flake8-docstrings + "DTZ003", # Use datetime.now(tz=) instead of datetime.utcnow() + "DTZ004", # Use datetime.fromtimestamp(ts, tz=) instead of datetime.utcfromtimestamp(ts) + "E", # pycodestyle + "F", # pyflakes/autoflake + "FLY", # flynt + "FURB", # refurb + "G", # flake8-logging-format + "I", # isort + "INP", # flake8-no-pep420 + "ISC", # flake8-implicit-str-concat + "ICN001", # import concentions; {name} should be imported as {asname} + "LOG", # flake8-logging + "N804", # First argument of a class method should be named cls + "N805", # First argument of a method should be named self + "N815", # Variable {name} in class scope should not be mixedCase + "PERF", # Perflint + "PGH", # pygrep-hooks + "PIE", # flake8-pie + "PL", # pylint + "PT", # flake8-pytest-style + "PTH", # flake8-use-pathlib + "PYI", # flake8-pyi + "RET", # flake8-return + "RSE", # flake8-raise + "RUF005", # Consider iterable unpacking instead of concatenation + "RUF006", # Store a reference to the return value of asyncio.create_task + "RUF010", # Use explicit conversion flag + "RUF013", # PEP 484 prohibits implicit Optional + "RUF017", # Avoid quadratic list summation + "RUF018", # Avoid assignment expressions in assert statements + "RUF019", # Unnecessary key check before dictionary access + # "RUF100", # Unused `noqa` directive; temporarily every now and then to clean them up + "S102", # Use of exec detected + "S103", # bad-file-permissions + "S108", # hardcoded-temp-file + "S306", # suspicious-mktemp-usage + "S307", # suspicious-eval-usage + "S313", # suspicious-xmlc-element-tree-usage + "S314", # suspicious-xml-element-tree-usage + "S315", # suspicious-xml-expat-reader-usage + "S316", # suspicious-xml-expat-builder-usage + "S317", # suspicious-xml-sax-usage + "S318", # suspicious-xml-mini-dom-usage + "S319", # suspicious-xml-pull-dom-usage + "S320", # suspicious-xmle-tree-usage + "S601", # paramiko-call + "S602", # subprocess-popen-with-shell-equals-true + "S604", # call-with-shell-equals-true + "S608", # hardcoded-sql-expression + "S609", # unix-command-wildcard-injection + "SIM", # flake8-simplify + "SLF", # flake8-self + "SLOT", # flake8-slots + "T100", # Trace found: {name} used + "TCH", # flake8-type-checking + "TID251", # Banned imports + "TRY", # tryceratops + "UP", # pyupgrade + "W", # pycodestyle +] +ignore = [ + "D202", # No blank lines allowed after function docstring + "D203", # 1 blank line required before class docstring + "D213", # Multi-line docstring summary should start at the second line + "PLR0911", # Too many return statements ({returns} > {max_returns}) + "PLR0912", # Too many branches ({branches} > {max_branches}) + "PLR0913", # Too many arguments to function call ({c_args} > {max_args}) + "PLR0915", # Too many statements ({statements} > {max_statements}) + "PLW2901", # Outer {outer_kind} variable {name} overwritten by inner {inner_kind} target + "TRY003", # Avoid specifying long messages outside the exception class + # May conflict with the formatter, https://docs.astral.sh/ruff/formatter/#conflicting-lint-rules + "W191", + "E111", + "E114", + "E117", + "D206", + "D300", + "Q", + "COM812", + "COM819", + "ISC001", +] + +[tool.ruff.lint.isort] +force-sort-within-sections = true +combine-as-imports = true +split-on-trailing-comma = false + +[tool.ruff.lint.flake8-pytest-style] +fixture-parentheses = false +mark-parentheses = false + +[tool.ruff.lint.mccabe] +max-complexity = 25 + +[tool.pylint.main] +py-version = "3.9" +load-plugins = [ + "pylint.extensions.code_style", + "pylint.extensions.typing", +] + [tool.pylint.master] extension-pkg-whitelist = [ "_socket", @@ -86,18 +191,19 @@ min-similarity-lines = 7 # Reasons disabled: # too-many-* - are not enforced for the sake of readability # too-few-* - same as too-many-* +# --- +# Pylint CodeStyle plugin +# consider-using-namedtuple-or-dataclass - too opinionated +# consider-using-assignment-expr - decision to use := better left to devs disable = [ "too-few-public-methods", "too-many-arguments", "too-many-instance-attributes", "too-many-locals", + "consider-using-namedtuple-or-dataclass", + "consider-using-assignment-expr", ] -[tool.isort] -profile = "black" -force_sort_within_sections = true -combine_as_imports = true - [tool.mypy] python_version = "3.9" show_error_codes = true diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 350a3e5..0000000 --- a/setup.cfg +++ /dev/null @@ -1,17 +0,0 @@ -[flake8] -doctests = True -# To work with Black -max-line-length = 88 -# E501: Line too long -# W503: Line break occurred before a binary operator -# E203: Whitespace before ':' -# D202: No blank lines allowed after function docstring -# W504: Line break after binary operator -# SIM119: Use a dataclass. It has many false-positives. -ignore = - E501, - W503, - E203, - D202, - W504, - SIM119 diff --git a/tests/assertions.py b/tests/assertions.py index 838d429..36b05c2 100644 --- a/tests/assertions.py +++ b/tests/assertions.py @@ -1,6 +1,4 @@ -""" -Common assertion helper classes used for unittesting -""" +"""Common assertion helper classes used for unittesting""" # pylint: disable=invalid-name from unittest import TestCase @@ -21,8 +19,7 @@ def assertDevice( homegraph_device: Device, homegraph_device_struct: GetHomeGraphResponse.Home.Device, ) -> None: - """ - Custom assertion because we create Device class object + """Custom assertion because we create Device class object for each of received homegraph devices, while in testing homegraph devices that we create are of type Struct """ diff --git a/tests/factory/providers.py b/tests/factory/providers.py index 10b6f55..65299b0 100644 --- a/tests/factory/providers.py +++ b/tests/factory/providers.py @@ -63,8 +63,7 @@ def homegraph_device( def homegraph_devices( self, min_devices: int = 1, max_devices: int = 10, count: int | None = None ) -> list[GetHomeGraphResponse.Home.Device]: - """ - Generates a random amount of devices, in the range specified. + """Generates a random amount of devices, in the range specified. min_devices: The number minimum of devices to generate. Should be greater than 0 diff --git a/tests/test_scanner.py b/tests/test_scanner.py index ffb856c..ca212c3 100644 --- a/tests/test_scanner.py +++ b/tests/test_scanner.py @@ -16,9 +16,7 @@ class NetworkDeviceTests(TestCase): - """ - NetworkDevice specific tests - """ + """NetworkDevice specific tests""" def test_initialization(self) -> None: """Initialization tests""" diff --git a/uv.lock b/uv.lock index 964d34d..c045f1e 100644 --- a/uv.lock +++ b/uv.lock @@ -6,15 +6,6 @@ resolution-markers = [ "python_full_version >= '3.12'", ] -[[package]] -name = "astor" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/21/75b771132fee241dfe601d39ade629548a9626d1d39f333fde31bc46febe/astor-0.8.1.tar.gz", hash = "sha256:6a6effda93f4e1ce9f618779b2dd1d9d84f1e32812c23a29b3fff6fd7f63fa5e", size = 35090 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c3/88/97eef84f48fa04fbd6750e62dcceafba6c63c81b7ac1420856c8dcc0a3f9/astor-0.8.1-py2.py3-none-any.whl", hash = "sha256:070a54e890cefb5b3739d19f30f5a5ec840ffc9c50ffa7d23cc9fc1a38ebbfc5", size = 27488 }, -] - [[package]] name = "astroid" version = "3.2.4" @@ -36,15 +27,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a7/fa/e01228c2938de91d47b307831c62ab9e4001e747789d0b05baf779a6488c/async_timeout-4.0.3-py3-none-any.whl", hash = "sha256:7405140ff1230c310e51dc27b3145b9092d659ce68ff733fb0cefe3ee42be028", size = 5721 }, ] -[[package]] -name = "attrs" -version = "24.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/fc/0f/aafca9af9315aee06a89ffde799a10a582fe8de76c563ee80bbcdc08b3fb/attrs-24.2.0.tar.gz", hash = "sha256:5cfb1b9148b5b086569baec03f20d7b6bf3bcacc9a42bebf87ffaaca362f6346", size = 792678 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/21/5b6702a7f963e95456c0de2d495f67bf5fd62840ac655dc451586d23d39a/attrs-24.2.0-py3-none-any.whl", hash = "sha256:81921eb96de3191c8258c199618104dd27ac608d9366f5e35d011eae1867ede2", size = 63001 }, -] - [[package]] name = "certifi" version = "2024.8.30" @@ -198,67 +180,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/95/f9310f35376024e1086c59cbb438d319fc9a4ef853289ce7c661539edbd4/filelock-3.16.0-py3-none-any.whl", hash = "sha256:f6ed4c963184f4c84dd5557ce8fece759a3724b37b80c6c4f20a2f63a4dc6609", size = 16170 }, ] -[[package]] -name = "flake8" -version = "7.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mccabe" }, - { name = "pycodestyle" }, - { name = "pyflakes" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/37/72/e8d66150c4fcace3c0a450466aa3480506ba2cae7b61e100a2613afc3907/flake8-7.1.1.tar.gz", hash = "sha256:049d058491e228e03e67b390f311bbf88fce2dbaa8fa673e7aea87b7198b8d38", size = 48054 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d9/42/65004373ac4617464f35ed15931b30d764f53cdd30cc78d5aea349c8c050/flake8-7.1.1-py2.py3-none-any.whl", hash = "sha256:597477df7860daa5aa0fdd84bf5208a043ab96b8e96ab708770ae0364dd03213", size = 57731 }, -] - -[[package]] -name = "flake8-bugbear" -version = "24.8.19" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "attrs" }, - { name = "flake8" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/b3/80043856ed90ceef0e95c01ed12d6bb7d4d76356e526450f0a9aeeb0a7b7/flake8_bugbear-24.8.19.tar.gz", hash = "sha256:9b77627eceda28c51c27af94560a72b5b2c97c016651bdce45d8f56c180d2d32", size = 78771 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2b/3c/8885a79ae7bebfab19716969de9810722ff45354e4ccc974a090bc478eaa/flake8_bugbear-24.8.19-py3-none-any.whl", hash = "sha256:25bc3867f7338ee3b3e0916bf8b8a0b743f53a9a5175782ddc4325ed4f386b89", size = 35357 }, -] - -[[package]] -name = "flake8-comprehensions" -version = "3.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "flake8" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/fa/68481f25fc8ecdbe8a763062ba4f5b17fa4ef7fc0646c081267cef4f67e5/flake8_comprehensions-3.15.0.tar.gz", hash = "sha256:923c22603e0310376a6b55b03efebdc09753c69f2d977755cba8bb73458a5d4d", size = 13079 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/aa/93667d6f398749d1a9dd37d646e092f9f1baade7cbac948331b50a1d513c/flake8_comprehensions-3.15.0-py3-none-any.whl", hash = "sha256:b7e027bbb52be2ceb779ee12484cdeef52b0ad3c1fcb8846292bdb86d3034681", size = 8162 }, -] - -[[package]] -name = "flake8-simplify" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "astor" }, - { name = "flake8" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/32/c0/4cd41ef29b5b19da0c87c1de6f7cbae3b238b991e0e12f2d65bf29eea34f/flake8_simplify-0.21.0.tar.gz", hash = "sha256:c95ff1dcc1de5949af47e0087cbf1164445881131b15bcd7a71252670f492f4d", size = 34055 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/c5/832d27af89939d06b43cf36138ffaf27e5b38e0d2b82183ef46110ebeb96/flake8_simplify-0.21.0-py3-none-any.whl", hash = "sha256:439391e762a9370b371208add0b5c5c40c3d25a98e1f5421d263215d08194183", size = 26884 }, -] - -[[package]] -name = "flake8-use-fstring" -version = "1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "flake8" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5c/40/ec0437e5ec5b107df0b6ee967b60e6f575a4d38c8b0639d78c555987fa39/flake8-use-fstring-1.4.tar.gz", hash = "sha256:6550bf722585eb97dffa8343b0f1c372101f5c4ab5b07ebf0edd1c79880cdd39", size = 5751 } - [[package]] name = "ghome-foyer-api" version = "1.0.0" @@ -274,7 +195,7 @@ wheels = [ [[package]] name = "glocaltokens" -version = "0.7.2.dev25+ge83580e.d20240913" +version = "0.7.2.dev27+gce652f9.d20240913" source = { editable = "." } dependencies = [ { name = "ghome-foyer-api" }, @@ -289,13 +210,7 @@ dependencies = [ dev = [ { name = "codespell" }, { name = "faker" }, - { name = "flake8" }, - { name = "flake8-bugbear" }, - { name = "flake8-comprehensions" }, - { name = "flake8-simplify" }, - { name = "flake8-use-fstring" }, { name = "grpc-stubs" }, - { name = "isort" }, { name = "mock" }, { name = "mypy" }, { name = "pre-commit" }, @@ -319,13 +234,7 @@ requires-dist = [ dev = [ { name = "codespell", specifier = ">=2.3.0" }, { name = "faker", specifier = ">=20.1.0" }, - { name = "flake8", specifier = ">=6.1.0" }, - { name = "flake8-bugbear", specifier = ">=23.12.2" }, - { name = "flake8-comprehensions", specifier = ">=3.15.0" }, - { name = "flake8-simplify", specifier = ">=0.21.0" }, - { name = "flake8-use-fstring", specifier = ">=1.4" }, { name = "grpc-stubs", specifier = ">=1.53.0.5" }, - { name = "isort", specifier = ">=5.13.2" }, { name = "mock", specifier = ">=5.1.0" }, { name = "mypy", specifier = ">=1.11.0" }, { name = "pre-commit", specifier = ">=3.8.0" }, @@ -579,15 +488,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/b5/95/0ba7f66934a0a798006f06fc3d74816da2b7a2bcfd9b98c53d26f684c89e/protobuf-4.25.4-py3-none-any.whl", hash = "sha256:bfbebc1c8e4793cfd58589acfb8a1026be0003e852b9da7db5a4285bde996978", size = 156464 }, ] -[[package]] -name = "pycodestyle" -version = "2.12.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/43/aa/210b2c9aedd8c1cbeea31a50e42050ad56187754b34eb214c46709445801/pycodestyle-2.12.1.tar.gz", hash = "sha256:6838eae08bbce4f6accd5d5572075c63626a15ee3e6f842df996bf62f6d73521", size = 39232 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/d8/a211b3f85e99a0daa2ddec96c949cac6824bd305b040571b82a03dd62636/pycodestyle-2.12.1-py2.py3-none-any.whl", hash = "sha256:46f0fb92069a7c28ab7bb558f05bfc0110dac69a0cd23c61ea0040283a9d78b3", size = 31284 }, -] - [[package]] name = "pycryptodomex" version = "3.20.0" @@ -616,15 +516,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4a/7b/881c25d94c821a83eedfa1a9193ff32f3436853f2daf7ce91a0d3d1aa74c/pycryptodomex-3.20.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:69138068268127cd605e03438312d8f271135a33140e2742b417d027a0539427", size = 1744358 }, ] -[[package]] -name = "pyflakes" -version = "3.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/57/f9/669d8c9c86613c9d568757c7f5824bd3197d7b1c6c27553bc5618a27cce2/pyflakes-3.2.0.tar.gz", hash = "sha256:1c61603ff154621fb2a9172037d84dca3500def8c8b630657d1701f026f8af3f", size = 63788 } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d4/d7/f1b7db88d8e4417c5d47adad627a93547f44bdc9028372dbd2313f34a855/pyflakes-3.2.0-py2.py3-none-any.whl", hash = "sha256:84b5be138a2dfbb40689ca07e2152deb896a65c3a3e24c251c5c62489568074a", size = 62725 }, -] - [[package]] name = "pylint" version = "3.2.7"