From dea3e5f1c4ddde8dfee1a798fc2d22dccc7ce543 Mon Sep 17 00:00:00 2001 From: ohemorange Date: Fri, 8 Aug 2025 08:48:43 -0700 Subject: [PATCH] Set up ruff so that test files have at least some linting (#10399) Alternative implementation for #7908. In this PR: - set up ruff in CI (add to `tox.ini`, mark dep in `certbot/setup.py`) - add a `ruff.toml` that ignores particularly annoying errors. I think line length isn't actually necessary to set with this workflow since we're not checking it but putting it there for future usage. - either fix or ignore the rest of the errors that come with the default linting configuration. fixed errors are mostly unused variables. ignored are usually where we're doing weird import things for a specific reason. --- acme/src/acme/__init__.py | 2 +- acme/src/acme/_internal/tests/client_test.py | 6 +-- .../acme/_internal/tests/crypto_util_test.py | 2 +- acme/src/acme/_internal/tests/jose_test.py | 4 +- acme/src/acme/client.py | 4 +- .../_internal/tests/configurator_test.py | 2 +- .../tests/parsernode_configurator_test.py | 7 +-- .../_internal/tests/parsernode_test.py | 4 +- .../utils/acme_server.py | 7 ++- .../utils/certbot_call.py | 5 +- .../_internal/tests/dns_route53_test.py | 1 - certbot/setup.py | 1 + certbot/src/certbot/_internal/cli/__init__.py | 1 + .../_internal/tests/auth_handler_test.py | 2 +- .../_internal/tests/cert_manager_test.py | 3 +- .../src/certbot/_internal/tests/cli_test.py | 9 ++-- .../certbot/_internal/tests/client_test.py | 2 +- .../_internal/tests/compat/filesystem_test.py | 2 +- .../src/certbot/_internal/tests/lock_test.py | 10 ++-- .../certbot/_internal/tests/renewal_test.py | 8 +-- certbot/src/certbot/compat/_path.py | 2 +- certbot/src/certbot/compat/os.py | 4 +- ruff.toml | 8 +++ tools/oldest_constraints.txt | 52 ++++++++++--------- tools/requirements.txt | 31 +++++------ tox.ini | 4 +- 26 files changed, 102 insertions(+), 81 deletions(-) create mode 100644 ruff.toml diff --git a/acme/src/acme/__init__.py b/acme/src/acme/__init__.py index 9a0f5d6e0..bd48fbfcd 100644 --- a/acme/src/acme/__init__.py +++ b/acme/src/acme/__init__.py @@ -13,7 +13,7 @@ import warnings # # It is based on # https://github.com/requests/requests/blob/1278ecdf71a312dc2268f3bfc0aabfab3c006dcf/requests/packages.py -import josepy as jose +import josepy as jose # noqa: F401 for mod in list(sys.modules): # This traversal is apparently necessary such that the identities are diff --git a/acme/src/acme/_internal/tests/client_test.py b/acme/src/acme/_internal/tests/client_test.py index 7d8f44f9c..ad7cd0c3e 100644 --- a/acme/src/acme/_internal/tests/client_test.py +++ b/acme/src/acme/_internal/tests/client_test.py @@ -293,7 +293,7 @@ class ClientV2Test(unittest.TestCase): updated_order_valid = self.order.update( certificate='https://www.letsencrypt-demo.org/acme/cert/', status=messages.STATUS_VALID) - updated_orderr = self.orderr.update(body=updated_order_valid, fullchain_pem=CERT_SAN_PEM) + self.orderr.update(body=updated_order_valid, fullchain_pem=CERT_SAN_PEM) self.response.text = CERT_SAN_PEM @@ -489,14 +489,14 @@ class ClientV2Test(unittest.TestCase): not_after=datetime.datetime(2025, 3, 20, 00, 00, 00), ) t, _ = self.client.renewal_time(cert_pem) - assert t == None + assert t is None cert_pem = make_cert_for_renewal( not_before=datetime.datetime(2025, 3, 12, 00, 00, 00), not_after=datetime.datetime(2025, 3, 30, 00, 00, 00), ) t, _ = self.client.renewal_time(cert_pem) - assert t == None + assert t is None @mock.patch('acme.client.datetime') def test_renewal_time_with_renewal_info(self, dt_mock): diff --git a/acme/src/acme/_internal/tests/crypto_util_test.py b/acme/src/acme/_internal/tests/crypto_util_test.py index d149cdb87..91438fdec 100644 --- a/acme/src/acme/_internal/tests/crypto_util_test.py +++ b/acme/src/acme/_internal/tests/crypto_util_test.py @@ -123,7 +123,7 @@ class GenMakeSelfSignedCertTest(unittest.TestCase): def test_no_ips(self): from acme.crypto_util import make_self_signed_cert - cert = make_self_signed_cert(self.privkey, ['dummy']) + make_self_signed_cert(self.privkey, ['dummy']) @mock.patch("acme.crypto_util._now") def test_expiry_times(self, mock_now): diff --git a/acme/src/acme/_internal/tests/jose_test.py b/acme/src/acme/_internal/tests/jose_test.py index 83787db15..3da1ece0a 100644 --- a/acme/src/acme/_internal/tests/jose_test.py +++ b/acme/src/acme/_internal/tests/jose_test.py @@ -20,9 +20,9 @@ def _test_it(submodule, attribute): # We use the imports below with eval, but pylint doesn't # understand that. - import josepy # pylint: disable=unused-import + import josepy # pylint: disable=unused-import # noqa: F401 - import acme # pylint: disable=unused-import + import acme # pylint: disable=unused-import # noqa: F401 acme_jose_mod = eval(acme_jose_path) # pylint: disable=eval-used josepy_mod = eval(josepy_path) # pylint: disable=eval-used assert acme_jose_mod is josepy_mod diff --git a/acme/src/acme/client.py b/acme/src/acme/client.py index 64c90e06e..4ce42b1ff 100644 --- a/acme/src/acme/client.py +++ b/acme/src/acme/client.py @@ -419,8 +419,8 @@ class ClientV2: if 'Link' not in response.headers: return [] links = parse_header_links(response.headers['Link']) - return [l['url'] for l in links - if 'rel' in l and 'url' in l and l['rel'] == relation_type] + return [link['url'] for link in links + if 'rel' in link and 'url' in link and link['rel'] == relation_type] @classmethod def get_directory(cls, url: str, net: 'ClientNetwork') -> messages.Directory: diff --git a/certbot-apache/src/certbot_apache/_internal/tests/configurator_test.py b/certbot-apache/src/certbot_apache/_internal/tests/configurator_test.py index 6a5595d31..1ec50e4da 100644 --- a/certbot-apache/src/certbot_apache/_internal/tests/configurator_test.py +++ b/certbot-apache/src/certbot_apache/_internal/tests/configurator_test.py @@ -1245,7 +1245,7 @@ class MultipleVhostsTest(util.ApacheTest): def test_deploy_cert_no_mod_ssl(self): # Create - ssl_vhost = self.config.make_vhost_ssl(self.vh_truth[0]) + self.config.make_vhost_ssl(self.vh_truth[0]) self.config.parser.modules["socache_shmcb_module"] = None self.config.prepare_server_https = mock.Mock() diff --git a/certbot-apache/src/certbot_apache/_internal/tests/parsernode_configurator_test.py b/certbot-apache/src/certbot_apache/_internal/tests/parsernode_configurator_test.py index 596b424f7..f6eaccd38 100644 --- a/certbot-apache/src/certbot_apache/_internal/tests/parsernode_configurator_test.py +++ b/certbot-apache/src/certbot_apache/_internal/tests/parsernode_configurator_test.py @@ -1,4 +1,5 @@ """Tests for ApacheConfigurator for AugeasParserNode classes""" +import importlib import sys import unittest from unittest import mock @@ -7,10 +8,10 @@ import pytest from certbot_apache._internal.tests import util -try: - import apacheconfig + +if importlib.util.find_spec('apacheconfig'): HAS_APACHECONFIG = True -except ImportError: # pragma: no cover +else: # pragma: no cover HAS_APACHECONFIG = False diff --git a/certbot-apache/src/certbot_apache/_internal/tests/parsernode_test.py b/certbot-apache/src/certbot_apache/_internal/tests/parsernode_test.py index d85e8c753..d9e20ee64 100644 --- a/certbot-apache/src/certbot_apache/_internal/tests/parsernode_test.py +++ b/certbot-apache/src/certbot_apache/_internal/tests/parsernode_test.py @@ -112,12 +112,12 @@ def test_dummy(): dirty=False, filepath="/some/random/path" ) - dummydirective = DummyDirectiveNode( + dummydirective = DummyDirectiveNode( # noqa: F841 name="Name", ancestor=None, filepath="/another/path" ) - dummycomment = DummyCommentNode( + dummycomment = DummyCommentNode( # noqa: F841 comment="Comment", ancestor=dummyblock, filepath="/some/file" diff --git a/certbot-ci/src/certbot_integration_tests/utils/acme_server.py b/certbot-ci/src/certbot_integration_tests/utils/acme_server.py index 130c398c7..b196fa8c6 100755 --- a/certbot-ci/src/certbot_integration_tests/utils/acme_server.py +++ b/certbot-ci/src/certbot_integration_tests/utils/acme_server.py @@ -24,7 +24,12 @@ from certbot_integration_tests.utils import misc from certbot_integration_tests.utils import pebble_artifacts from certbot_integration_tests.utils import pebble_ocsp_server from certbot_integration_tests.utils import proxy -from certbot_integration_tests.utils.constants import * +from certbot_integration_tests.utils.constants import DEFAULT_HTTP_01_PORT +from certbot_integration_tests.utils.constants import CHALLTESTSRV_PORT +from certbot_integration_tests.utils.constants import PEBBLE_DIRECTORY_URL +from certbot_integration_tests.utils.constants import PEBBLE_CHALLTESTSRV_URL +from certbot_integration_tests.utils.constants import PEBBLE_ALTERNATE_ROOTS +from certbot_integration_tests.utils.constants import MAX_SUBPROCESS_WAIT class ACMEServer: diff --git a/certbot-ci/src/certbot_integration_tests/utils/certbot_call.py b/certbot-ci/src/certbot_integration_tests/utils/certbot_call.py index 07b6d4182..2fc6021a7 100755 --- a/certbot-ci/src/certbot_integration_tests/utils/certbot_call.py +++ b/certbot-ci/src/certbot_integration_tests/utils/certbot_call.py @@ -10,8 +10,9 @@ from typing import Optional from typing import Tuple import certbot_integration_tests -# pylint: disable=wildcard-import,unused-wildcard-import -from certbot_integration_tests.utils.constants import * +from certbot_integration_tests.utils.constants import DEFAULT_HTTP_01_PORT +from certbot_integration_tests.utils.constants import HTTPS_PORT +from certbot_integration_tests.utils.constants import PEBBLE_DIRECTORY_URL def certbot_test(certbot_args: List[str], directory_url: Optional[str], http_01_port: int, diff --git a/certbot-dns-route53/src/certbot_dns_route53/_internal/tests/dns_route53_test.py b/certbot-dns-route53/src/certbot_dns_route53/_internal/tests/dns_route53_test.py index 95a90434f..e6df0c93e 100644 --- a/certbot-dns-route53/src/certbot_dns_route53/_internal/tests/dns_route53_test.py +++ b/certbot-dns-route53/src/certbot_dns_route53/_internal/tests/dns_route53_test.py @@ -17,7 +17,6 @@ from certbot.plugins.dns_test_common import DOMAIN from certbot.tests import acme_util from certbot.tests import util as test_util -DOMAIN = 'example.com' KEY = jose.jwk.JWKRSA.load(test_util.load_vector("rsa512_key.pem")) diff --git a/certbot/setup.py b/certbot/setup.py index 170626363..587266717 100644 --- a/certbot/setup.py +++ b/certbot/setup.py @@ -71,6 +71,7 @@ test_extras = [ 'pytest', 'pytest-cov', 'pytest-xdist', + 'ruff', 'setuptools', 'tox', 'types-httplib2', diff --git a/certbot/src/certbot/_internal/cli/__init__.py b/certbot/src/certbot/_internal/cli/__init__.py index 63f951150..31964153f 100644 --- a/certbot/src/certbot/_internal/cli/__init__.py +++ b/certbot/src/certbot/_internal/cli/__init__.py @@ -1,5 +1,6 @@ """Certbot command line argument & config processing.""" # pylint: disable=too-many-lines +# ruff: noqa: F401 import argparse import logging import logging.handlers diff --git a/certbot/src/certbot/_internal/tests/auth_handler_test.py b/certbot/src/certbot/_internal/tests/auth_handler_test.py index 0a61c8e8e..6c8a2d808 100644 --- a/certbot/src/certbot/_internal/tests/auth_handler_test.py +++ b/certbot/src/certbot/_internal/tests/auth_handler_test.py @@ -51,7 +51,7 @@ class ChallengeFactoryTest(unittest.TestCase): [messages.STATUS_PENDING]) achalls = self.handler._challenge_factory(authzr, [0]) - assert type(achalls[0]) == achallenges.Other + assert type(achalls[0]) is achallenges.Other class HandleAuthorizationsTest(unittest.TestCase): diff --git a/certbot/src/certbot/_internal/tests/cert_manager_test.py b/certbot/src/certbot/_internal/tests/cert_manager_test.py index fae9de8d8..a079141c0 100644 --- a/certbot/src/certbot/_internal/tests/cert_manager_test.py +++ b/certbot/src/certbot/_internal/tests/cert_manager_test.py @@ -226,7 +226,8 @@ class CertificatesTest(BaseCertManagerTest): # pylint: disable=protected-access # pylint: disable=protected-access - get_report = lambda: cert_manager._report_human_readable(mock_config, parsed_certs) + def get_report(): + return cert_manager._report_human_readable(mock_config, parsed_certs) out = get_report() assert "INVALID: EXPIRED" in out diff --git a/certbot/src/certbot/_internal/tests/cli_test.py b/certbot/src/certbot/_internal/tests/cli_test.py index 5602734f3..f55ae65be 100644 --- a/certbot/src/certbot/_internal/tests/cli_test.py +++ b/certbot/src/certbot/_internal/tests/cli_test.py @@ -117,11 +117,10 @@ class ParseTest(unittest.TestCase): with tempfile.NamedTemporaryFile() as tmp_config: tmp_config.close() # close now because of compatibility issues on Windows # use a shim to get ConfigArgParse to pick up tmp_config - shim = ( - lambda v: copy.deepcopy(constants.CLI_DEFAULTS[v]) - if v != "config_files" - else [tmp_config.name] - ) + def shim(v): + return (copy.deepcopy(constants.CLI_DEFAULTS[v]) + if v != "config_files" + else [tmp_config.name]) mock_flag_default.side_effect = shim namespace = self.parse(["certonly"]) diff --git a/certbot/src/certbot/_internal/tests/client_test.py b/certbot/src/certbot/_internal/tests/client_test.py index 3c4197234..9b92c0c43 100644 --- a/certbot/src/certbot/_internal/tests/client_test.py +++ b/certbot/src/certbot/_internal/tests/client_test.py @@ -1061,7 +1061,7 @@ class EnhanceConfigTest(ClientTestCommon): def _test_error(self, enhance_error=False, restart_error=False): self.config.redirect = True with mock.patch('certbot._internal.client.logger') as mock_logger, \ - test_util.patch_display_util() as mock_gu: + test_util.patch_display_util(): with pytest.raises(errors.PluginError): self._test_with_all_supported() diff --git a/certbot/src/certbot/_internal/tests/compat/filesystem_test.py b/certbot/src/certbot/_internal/tests/compat/filesystem_test.py index 2f5d4e7e5..565f17087 100644 --- a/certbot/src/certbot/_internal/tests/compat/filesystem_test.py +++ b/certbot/src/certbot/_internal/tests/compat/filesystem_test.py @@ -565,7 +565,7 @@ class RealpathTest(test_util.TempDirTestCase): os.symlink(link2_path, link3_path) os.symlink(link3_path, link1_path) - with pytest.raises(RuntimeError, match='link1 is a loop!') as error: + with pytest.raises(RuntimeError, match='link1 is a loop!'): filesystem.realpath(link1_path) diff --git a/certbot/src/certbot/_internal/tests/lock_test.py b/certbot/src/certbot/_internal/tests/lock_test.py index f8ff8b59a..9a56e31a1 100644 --- a/certbot/src/certbot/_internal/tests/lock_test.py +++ b/certbot/src/certbot/_internal/tests/lock_test.py @@ -1,5 +1,6 @@ """Tests for certbot._internal.lock.""" import functools +import importlib import multiprocessing import sys from unittest import mock @@ -10,13 +11,10 @@ from certbot import errors from certbot.compat import os from certbot.tests import util as test_util -try: - import fcntl # pylint: disable=import-error,unused-import -except ImportError: - POSIX_MODE = False -else: +if importlib.util.find_spec('fcntl'): POSIX_MODE = True - +else: + POSIX_MODE = False diff --git a/certbot/src/certbot/_internal/tests/renewal_test.py b/certbot/src/certbot/_internal/tests/renewal_test.py index a0f2facd1..a6b1449c4 100644 --- a/certbot/src/certbot/_internal/tests/renewal_test.py +++ b/certbot/src/certbot/_internal/tests/renewal_test.py @@ -198,7 +198,7 @@ class RenewalTest(test_util.ConfigTestCase): from certbot._internal import renewal lineage_config = copy.deepcopy(self.config) - renewal_candidate = renewal.reconstitute(lineage_config, rc_path) + renewal.reconstitute(lineage_config, rc_path) # This means that manual_public_ip_logging_ok was not modified in the config based on its # value in the renewal conf file assert isinstance(lineage_config.manual_public_ip_logging_ok, mock.MagicMock) @@ -233,7 +233,7 @@ class RenewalTest(test_util.ConfigTestCase): test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf', ec=False) config = configuration.NamespaceConfig(self.config) - with mock.patch('time.sleep') as sleep: + with mock.patch('time.sleep'): renewal.handle_renewal_request(config) mock_renew_cert.assert_called_once() @@ -254,7 +254,7 @@ class RenewalTest(test_util.ConfigTestCase): test_util.make_lineage(self.config.config_dir, 'sample-renewal.conf', ec=False) - with mock.patch('time.sleep') as sleep: + with mock.patch('time.sleep'): renewal.handle_renewal_request(self.config) assert mock_client_network_get.call_count == 0 @@ -265,7 +265,7 @@ class RenewalTest(test_util.ConfigTestCase): self.config.dry_run = True ari_client_pool = mock.MagicMock() ari_client_pool.get.return_value = mock_acme - with mock.patch('time.sleep') as sleep: + with mock.patch('time.sleep'): renewal.should_renew(self.config, mock.Mock(), ari_client_pool) assert mock_acme.renewal_time.call_count == 0 diff --git a/certbot/src/certbot/compat/_path.py b/certbot/src/certbot/compat/_path.py index c36421b7e..bc37833af 100644 --- a/certbot/src/certbot/compat/_path.py +++ b/certbot/src/certbot/compat/_path.py @@ -13,7 +13,7 @@ from __future__ import absolute_import # First round of wrapping: we import statically all public attributes exposed by the os.path # module. This allows in particular to have pylint, mypy, IDEs be aware that most of os.path # members are available in certbot.compat.path. -from os.path import * # pylint: disable=wildcard-import,unused-wildcard-import,os-module-forbidden +from os.path import * # pylint: disable=wildcard-import,unused-wildcard-import,os-module-forbidden # noqa: F403 # Second round of wrapping: we import dynamically all attributes from the os.path module that have # not yet been imported by the first round (static star import). diff --git a/certbot/src/certbot/compat/os.py b/certbot/src/certbot/compat/os.py index 3aa9a527f..82f570459 100644 --- a/certbot/src/certbot/compat/os.py +++ b/certbot/src/certbot/compat/os.py @@ -21,7 +21,7 @@ from __future__ import absolute_import # First round of wrapping: we import statically all public attributes exposed by the os module # This allows in particular to have pylint, mypy, IDEs be aware that most of os members are # available in certbot.compat.os. -from os import * # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin,os-module-forbidden +from os import * # pylint: disable=wildcard-import,unused-wildcard-import,redefined-builtin,os-module-forbidden # noqa: F403 # Second round of wrapping: we import dynamically all attributes from the os module that have not # yet been imported by the first round (static import). This covers in particular the case of @@ -43,7 +43,7 @@ if not std_os.environ.get("CERTBOT_DOCS") == "1": # Import our internal path module, then allow certbot.compat.os.path # to behave as a module (similarly to os.path). -from certbot.compat import _path as path # type: ignore # pylint: disable=wrong-import-position +from certbot.compat import _path as path # type: ignore # pylint: disable=wrong-import-position # noqa: E402 std_sys.modules[__name__ + '.path'] = path # Clean all remaining importables that are not from the core os module. diff --git a/ruff.toml b/ruff.toml new file mode 100644 index 000000000..5fb3b891f --- /dev/null +++ b/ruff.toml @@ -0,0 +1,8 @@ +line-length = 100 + +extend-exclude = ['tools', 'letstest'] + +[lint] +# Skip bare `except` rules (`E722`). +# Skip ambiguous variable name (`E741`). +ignore = ["E722", "E741",] diff --git a/tools/oldest_constraints.txt b/tools/oldest_constraints.txt index 12066cbe3..3d7c84716 100644 --- a/tools/oldest_constraints.txt +++ b/tools/oldest_constraints.txt @@ -2,28 +2,28 @@ # that script. apacheconfig==0.3.2 ; python_full_version >= "3.9.2" and python_version < "3.10" asn1crypto==0.24.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -astroid==3.3.9 ; python_full_version >= "3.9.2" and python_version < "3.10" +astroid==3.3.11 ; python_full_version >= "3.9.2" and python_version < "3.10" attrs==25.3.0 ; python_full_version >= "3.9.2" and python_version < "3.10" beautifulsoup4==4.13.4 ; python_full_version >= "3.9.2" and python_version < "3.10" boto3==1.15.15 ; python_full_version >= "3.9.2" and python_version < "3.10" botocore==1.18.15 ; python_full_version >= "3.9.2" and python_version < "3.10" cachetools==5.5.2 ; python_full_version >= "3.9.2" and python_version < "3.10" -certifi==2025.4.26 ; python_full_version >= "3.9.2" and python_version < "3.10" +certifi==2025.8.3 ; python_full_version >= "3.9.2" and python_version < "3.10" cffi==1.12.3 ; python_full_version >= "3.9.2" and python_version < "3.10" chardet==3.0.4 ; python_full_version >= "3.9.2" and python_version < "3.10" cloudflare==2.19.0 ; python_full_version >= "3.9.2" and python_version < "3.10" colorama==0.4.6 ; python_full_version >= "3.9.2" and python_version < "3.10" and sys_platform == "win32" configargparse==1.5.3 ; python_full_version >= "3.9.2" and python_version < "3.10" configobj==5.0.6 ; python_full_version >= "3.9.2" and python_version < "3.10" -coverage==7.8.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +coverage==7.10.2 ; python_full_version >= "3.9.2" and python_version < "3.10" cryptography==43.0.0 ; python_full_version >= "3.9.2" and python_version < "3.10" cython==0.29.37 ; python_full_version >= "3.9.2" and python_version < "3.10" dill==0.4.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -distlib==0.3.9 ; python_full_version >= "3.9.2" and python_version < "3.10" +distlib==0.4.0 ; python_full_version >= "3.9.2" and python_version < "3.10" distro==1.0.1 ; python_full_version >= "3.9.2" and python_version < "3.10" dns-lexicon==3.15.1 ; python_full_version >= "3.9.2" and python_version < "3.10" dnspython==2.6.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -exceptiongroup==1.2.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +exceptiongroup==1.3.0 ; python_full_version >= "3.9.2" and python_version < "3.10" execnet==2.1.1 ; python_full_version >= "3.9.2" and python_version < "3.10" filelock==3.18.0 ; python_full_version >= "3.9.2" and python_version < "3.10" funcsigs==0.4 ; python_full_version >= "3.9.2" and python_version < "3.10" @@ -37,58 +37,62 @@ iniconfig==2.1.0 ; python_full_version >= "3.9.2" and python_version < "3.10" ipaddress==1.0.16 ; python_full_version >= "3.9.2" and python_version < "3.10" isort==6.0.1 ; python_full_version >= "3.9.2" and python_version < "3.10" jmespath==0.10.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -josepy==2.0.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +josepy==2.1.0 ; python_full_version >= "3.9.2" and python_version < "3.10" jsonlines==4.0.0 ; python_full_version >= "3.9.2" and python_version < "3.10" mccabe==0.7.0 ; python_full_version >= "3.9.2" and python_version < "3.10" mypy-extensions==1.1.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -mypy==1.15.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +mypy==1.17.1 ; python_full_version >= "3.9.2" and python_version < "3.10" ndg-httpsclient==0.3.2 ; python_full_version >= "3.9.2" and python_version < "3.10" oauth2client==4.1.3 ; python_full_version >= "3.9.2" and python_version < "3.10" packaging==25.0 ; python_full_version >= "3.9.2" and python_version < "3.10" parsedatetime==2.4 ; python_full_version >= "3.9.2" and python_version < "3.10" +pathspec==0.12.1 ; python_full_version >= "3.9.2" and python_version < "3.10" pbr==1.8.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -pip==25.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -platformdirs==4.3.7 ; python_full_version >= "3.9.2" and python_version < "3.10" -pluggy==1.5.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +pip==25.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +platformdirs==4.3.8 ; python_full_version >= "3.9.2" and python_version < "3.10" +pluggy==1.6.0 ; python_full_version >= "3.9.2" and python_version < "3.10" ply==3.4 ; python_full_version >= "3.9.2" and python_version < "3.10" py==1.11.0 ; python_full_version >= "3.9.2" and python_version < "3.10" pyasn1-modules==0.4.1 ; python_full_version >= "3.9.2" and python_version < "3.10" pyasn1==0.4.8 ; python_full_version >= "3.9.2" and python_version < "3.10" pycparser==2.14 ; python_full_version >= "3.9.2" and python_version < "3.10" -pylint==3.3.6 ; python_full_version >= "3.9.2" and python_version < "3.10" +pygments==2.19.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +pylint==3.3.7 ; python_full_version >= "3.9.2" and python_version < "3.10" pyopenssl==25.0.0 ; python_full_version >= "3.9.2" and python_version < "3.10" pyotp==2.9.0 ; python_full_version >= "3.9.2" and python_version < "3.10" pyparsing==2.4.7 ; python_full_version >= "3.9.2" and python_version < "3.10" pyrfc3339==1.0 ; python_full_version >= "3.9.2" and python_version < "3.10" -pytest-cov==6.1.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -pytest-xdist==3.6.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -pytest==8.3.5 ; python_full_version >= "3.9.2" and python_version < "3.10" +pytest-cov==6.2.1 ; python_full_version >= "3.9.2" and python_version < "3.10" +pytest-xdist==3.8.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +pytest==8.4.1 ; python_full_version >= "3.9.2" and python_version < "3.10" python-augeas==0.5.0 ; python_full_version >= "3.9.2" and python_version < "3.10" python-dateutil==2.9.0.post0 ; python_full_version >= "3.9.2" and python_version < "3.10" python-digitalocean==1.11 ; python_full_version >= "3.9.2" and python_version < "3.10" -pywin32==310 ; python_full_version >= "3.9.2" and python_version < "3.10" and sys_platform == "win32" +pytz==2025.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +pywin32==311 ; python_full_version >= "3.9.2" and python_version < "3.10" and sys_platform == "win32" pyyaml==6.0.2 ; python_full_version >= "3.9.2" and python_version < "3.10" requests-file==2.1.0 ; python_full_version >= "3.9.2" and python_version < "3.10" requests==2.20.0 ; python_full_version >= "3.9.2" and python_version < "3.10" rsa==4.9.1 ; python_full_version >= "3.9.2" and python_version < "3.10" +ruff==0.12.8 ; python_full_version >= "3.9.2" and python_version < "3.10" s3transfer==0.3.7 ; python_full_version >= "3.9.2" and python_version < "3.10" -setuptools==80.0.1 ; python_full_version >= "3.9.2" and python_version < "3.10" +setuptools==80.9.0 ; python_full_version >= "3.9.2" and python_version < "3.10" six==1.11.0 ; python_full_version >= "3.9.2" and python_version < "3.10" soupsieve==2.7 ; python_full_version >= "3.9.2" and python_version < "3.10" tldextract==5.3.0 ; python_full_version >= "3.9.2" and python_version < "3.10" tomli==2.2.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -tomlkit==0.13.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +tomlkit==0.13.3 ; python_full_version >= "3.9.2" and python_version < "3.10" tox==1.9.2 ; python_full_version >= "3.9.2" and python_version < "3.10" -types-httplib2==0.22.0.20250401 ; python_full_version >= "3.9.2" and python_version < "3.10" +types-httplib2==0.22.0.20250622 ; python_full_version >= "3.9.2" and python_version < "3.10" types-pyrfc3339==2.0.1.20241107 ; python_full_version >= "3.9.2" and python_version < "3.10" -types-python-dateutil==2.9.0.20241206 ; python_full_version >= "3.9.2" and python_version < "3.10" -types-pywin32==310.0.0.20250429 ; python_full_version >= "3.9.2" and python_version < "3.10" +types-python-dateutil==2.9.0.20250708 ; python_full_version >= "3.9.2" and python_version < "3.10" +types-pywin32==311.0.0.20250801 ; python_full_version >= "3.9.2" and python_version < "3.10" types-requests==2.31.0.6 ; python_full_version >= "3.9.2" and python_version < "3.10" -types-setuptools==80.0.0.20250429 ; python_full_version >= "3.9.2" and python_version < "3.10" +types-setuptools==80.9.0.20250801 ; python_full_version >= "3.9.2" and python_version < "3.10" types-urllib3==1.26.25.14 ; python_full_version >= "3.9.2" and python_version < "3.10" -typing-extensions==4.13.2 ; python_full_version >= "3.9.2" and python_version < "3.10" +typing-extensions==4.14.1 ; python_full_version >= "3.9.2" and python_version < "3.10" uritemplate==3.0.1 ; python_full_version >= "3.9.2" and python_version < "3.10" urllib3==1.24.2 ; python_full_version >= "3.9.2" and python_version < "3.10" -virtualenv==20.30.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +virtualenv==20.33.1 ; python_full_version >= "3.9.2" and python_version < "3.10" wheel==0.45.1 ; python_full_version >= "3.9.2" and python_version < "3.10" -zipp==3.21.0 ; python_full_version >= "3.9.2" and python_version < "3.10" +zipp==3.23.0 ; python_full_version >= "3.9.2" and python_version < "3.10" diff --git a/tools/requirements.txt b/tools/requirements.txt index e2b7b6153..fbce7ddf8 100644 --- a/tools/requirements.txt +++ b/tools/requirements.txt @@ -7,7 +7,7 @@ # for more info. alabaster==0.7.16 ; python_full_version >= "3.9.2" and python_version < "3.10" alabaster==1.0.0 ; python_version >= "3.10" and python_version < "4.0" -anyio==4.9.0 ; python_full_version >= "3.9.2" and python_version < "4.0" +anyio==4.10.0 ; python_full_version >= "3.9.2" and python_version < "4.0" apacheconfig==0.3.2 ; python_full_version >= "3.9.2" and python_version < "4.0" astroid==3.3.11 ; python_full_version >= "3.9.2" and python_version < "4.0" asttokens==3.0.0 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -18,12 +18,12 @@ babel==2.17.0 ; python_full_version >= "3.9.2" and python_version < "4.0" backports-tarfile==1.2.0 ; python_full_version >= "3.9.2" and python_version < "3.12" bcrypt==4.3.0 ; python_full_version >= "3.9.2" and python_version < "4.0" beautifulsoup4==4.13.4 ; python_full_version >= "3.9.2" and python_version < "4.0" -boto3==1.39.16 ; python_full_version >= "3.9.2" and python_version < "4.0" -botocore==1.39.16 ; python_full_version >= "3.9.2" and python_version < "4.0" -build==1.2.2.post1 ; python_full_version >= "3.9.2" and python_version < "4.0" +boto3==1.40.5 ; python_full_version >= "3.9.2" and python_version < "4.0" +botocore==1.40.5 ; python_full_version >= "3.9.2" and python_version < "4.0" +build==1.3.0 ; python_full_version >= "3.9.2" and python_version < "4.0" cachecontrol==0.14.3 ; python_full_version >= "3.9.2" and python_version < "4.0" cachetools==5.5.2 ; python_full_version >= "3.9.2" and python_version < "4.0" -certifi==2025.7.14 ; python_full_version >= "3.9.2" and python_version < "4.0" +certifi==2025.8.3 ; python_full_version >= "3.9.2" and python_version < "4.0" cffi==1.17.1 ; python_full_version >= "3.9.2" and python_version < "4.0" chardet==5.2.0 ; python_full_version >= "3.9.2" and python_version < "4.0" charset-normalizer==3.4.2 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -34,9 +34,9 @@ cloudflare==2.19.4 ; python_full_version >= "3.9.2" and python_version < "4.0" colorama==0.4.6 ; python_full_version >= "3.9.2" and python_version < "4.0" configargparse==1.7.1 ; python_full_version >= "3.9.2" and python_version < "4.0" configobj==5.0.9 ; python_full_version >= "3.9.2" and python_version < "4.0" -coverage==7.10.1 ; python_full_version >= "3.9.2" and python_version < "4.0" +coverage==7.10.2 ; python_full_version >= "3.9.2" and python_version < "4.0" crashtest==0.4.1 ; python_full_version >= "3.9.2" and python_version < "4.0" -cryptography==45.0.5 ; python_full_version >= "3.9.2" and python_version < "4.0" +cryptography==45.0.6 ; python_full_version >= "3.9.2" and python_version < "4.0" cython==0.29.37 ; python_full_version >= "3.9.2" and python_version < "4.0" decorator==5.2.1 ; python_full_version >= "3.9.2" and python_version < "4.0" deprecated==1.2.18 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -55,7 +55,7 @@ fastjsonschema==2.21.1 ; python_full_version >= "3.9.2" and python_version < "4. filelock==3.18.0 ; python_full_version >= "3.9.2" and python_version < "4.0" findpython==0.6.3 ; python_full_version >= "3.9.2" and python_version < "4.0" google-api-core==2.25.1 ; python_full_version >= "3.9.2" and python_version < "4.0" -google-api-python-client==2.177.0 ; python_full_version >= "3.9.2" and python_version < "4.0" +google-api-python-client==2.178.0 ; python_full_version >= "3.9.2" and python_version < "4.0" google-auth-httplib2==0.2.0 ; python_full_version >= "3.9.2" and python_version < "4.0" google-auth==2.40.3 ; python_full_version >= "3.9.2" and python_version < "4.0" googleapis-common-protos==1.70.0 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -103,19 +103,19 @@ mypy==1.9.0 ; python_full_version >= "3.9.2" and python_version < "4.0" nh3==0.3.0 ; python_full_version >= "3.9.2" and python_version < "4.0" oauthlib==3.3.1 ; python_full_version >= "3.9.2" and python_version < "4.0" packaging==25.0 ; python_full_version >= "3.9.2" and python_version < "4.0" -paramiko==3.5.1 ; python_full_version >= "3.9.2" and python_version < "4.0" +paramiko==4.0.0 ; python_full_version >= "3.9.2" and python_version < "4.0" parsedatetime==2.6 ; python_full_version >= "3.9.2" and python_version < "4.0" parso==0.8.4 ; python_full_version >= "3.9.2" and python_version < "4.0" -pbs-installer==2025.7.23 ; python_full_version >= "3.9.2" and python_version < "4.0" +pbs-installer==2025.8.7 ; python_full_version >= "3.9.2" and python_version < "4.0" pexpect==4.9.0 ; python_full_version >= "3.9.2" and python_version < "4.0" and (sys_platform != "win32" and sys_platform != "emscripten" or python_version < "3.10") and sys_platform != "win32" -pip==25.1.1 ; python_full_version >= "3.9.2" and python_version < "4.0" +pip==25.2 ; python_full_version >= "3.9.2" and python_version < "4.0" pkginfo==1.12.1.2 ; python_full_version >= "3.9.2" and python_version < "4.0" platformdirs==4.3.8 ; python_full_version >= "3.9.2" and python_version < "4.0" pluggy==1.6.0 ; python_full_version >= "3.9.2" and python_version < "4.0" ply==3.11 ; python_full_version >= "3.9.2" and python_version < "4.0" poetry-core==2.1.3 ; python_full_version >= "3.9.2" and python_version < "4.0" poetry-plugin-export==1.9.0 ; python_full_version >= "3.9.2" and python_version < "4.0" -poetry==2.1.3 ; python_full_version >= "3.9.2" and python_version < "4.0" +poetry==2.1.4 ; python_full_version >= "3.9.2" and python_version < "4.0" prompt-toolkit==3.0.51 ; python_full_version >= "3.9.2" and python_version < "4.0" proto-plus==1.26.1 ; python_full_version >= "3.9.2" and python_version < "4.0" protobuf==6.31.1 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -152,6 +152,7 @@ rfc3986==2.0.0 ; python_full_version >= "3.9.2" and python_version < "4.0" rich==14.1.0 ; python_full_version >= "3.9.2" and python_version < "4.0" roman-numerals-py==3.1.0 ; python_version >= "3.11" and python_version < "4.0" rsa==4.9.1 ; python_full_version >= "3.9.2" and python_version < "4.0" +ruff==0.12.8 ; python_full_version >= "3.9.2" and python_version < "4.0" s3transfer==0.13.1 ; python_full_version >= "3.9.2" and python_version < "4.0" secretstorage==3.3.3 ; python_full_version >= "3.9.2" and python_version < "4.0" and sys_platform == "linux" semantic-version==2.10.0 ; python_full_version >= "3.9.2" and python_version < "4.0" @@ -180,15 +181,15 @@ tomlkit==0.13.3 ; python_full_version >= "3.9.2" and python_version < "4.0" towncrier==24.8.0 ; python_full_version >= "3.9.2" and python_version < "4.0" tox==4.27.0 ; python_full_version >= "3.9.2" and python_version < "4.0" traitlets==5.14.3 ; python_full_version >= "3.9.2" and python_version < "4.0" -trove-classifiers==2025.5.9.12 ; python_full_version >= "3.9.2" and python_version < "4.0" +trove-classifiers==2025.8.6.13 ; python_full_version >= "3.9.2" and python_version < "4.0" twine==6.1.0 ; python_full_version >= "3.9.2" and python_version < "4.0" types-httplib2==0.22.0.20250622 ; python_full_version >= "3.9.2" and python_version < "4.0" types-pyrfc3339==2.0.1.20241107 ; python_full_version >= "3.9.2" and python_version < "4.0" types-python-dateutil==2.9.0.20250708 ; python_full_version >= "3.9.2" and python_version < "4.0" -types-pywin32==311.0.0.20250728 ; python_full_version >= "3.9.2" and python_version < "4.0" +types-pywin32==311.0.0.20250801 ; python_full_version >= "3.9.2" and python_version < "4.0" types-requests==2.31.0.6 ; python_full_version >= "3.9.2" and python_version < "3.10" types-requests==2.32.4.20250611 ; python_version >= "3.10" and python_version < "4.0" -types-setuptools==80.9.0.20250529 ; python_full_version >= "3.9.2" and python_version < "4.0" +types-setuptools==80.9.0.20250801 ; python_full_version >= "3.9.2" and python_version < "4.0" types-urllib3==1.26.25.14 ; python_full_version >= "3.9.2" and python_version < "3.10" typing-extensions==4.14.1 ; python_full_version >= "3.9.2" and python_version < "4.0" uritemplate==4.2.0 ; python_full_version >= "3.9.2" and python_version < "4.0" diff --git a/tox.ini b/tox.ini index 29e1dcf25..f74c56d99 100644 --- a/tox.ini +++ b/tox.ini @@ -98,7 +98,9 @@ commands = commands = {[testenv:cover]commands} [testenv:lint{,-posix}] -commands = python -m pylint --reports=n --rcfile=.pylintrc {[base]source_paths} +commands = + python -m pylint --reports=n --rcfile=.pylintrc {[base]source_paths} + ruff check [testenv:mypy] deps =