Skip to content

Replace flake8+isort+black with ruff #3147

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 0 additions & 28 deletions .flake8

This file was deleted.

5 changes: 0 additions & 5 deletions .isort.cfg

This file was deleted.

2 changes: 1 addition & 1 deletion benchmarks/basic_operations.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ def wrapper(*args, **kwargs):
count = args[1]
print(f"{func.__name__} - {count} Requests")
print(f"Duration = {duration}")
print(f"Rate = {count/duration}")
print(f"Rate = {count / duration}")
print()
return ret

Expand Down
1 change: 0 additions & 1 deletion benchmarks/command_packer_benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,6 @@ def pack_command(self, *args):


class CommandPackerBenchmark(Benchmark):

ARGUMENTS = (
{
"name": "connection_class",
Expand Down
1 change: 0 additions & 1 deletion benchmarks/socket_read_size.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@


class SocketReadBenchmark(Benchmark):

ARGUMENTS = (
{"name": "parser", "values": [PythonParser, _HiredisParser]},
{
Expand Down
5 changes: 1 addition & 4 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,5 @@
build
black==24.3.0
click==8.0.4
flake8-isort
flake8
flynt~=0.69.0
invoke==2.2.0
mock
packaging>=20.4
Expand All @@ -12,6 +8,7 @@ pytest-asyncio>=0.23.0,<0.24.0
pytest-cov
pytest-profiling==1.8.1
pytest-timeout
ruff==0.9.6
ujson>=4.2.0
uvloop
vulture>=2.3.0
Expand Down
4 changes: 2 additions & 2 deletions doctests/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ pip uninstall -y redis # uninstall Redis package installed via redis-entraid
pip install -r doctests/requirements.txt
```

Note - the CI process, runs the basic ```black``` and ```isort``` linters against the examples. Assuming
the requirements above have been installed you can run ```black yourfile.py``` and ```isort yourfile.py```
Note - the CI process, runs linters against the examples. Assuming
the requirements above have been installed you can run ```ruff check yourfile.py``` and ```ruff format yourfile.py```
locally to validate the linting, prior to CI.

Just include necessary assertions in the example file and run
Expand Down
50 changes: 50 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -96,3 +96,53 @@ filterwarnings = [
# Ignore a coverage warning when COVERAGE_CORE=sysmon for Pythons < 3.12.
"ignore:sys.monitoring isn't available:coverage.exceptions.CoverageWarning",
]

[tool.ruff]
target-version = "py38"
line-length = 88
exclude = [
"*.egg-info",
"*.pyc",
".git",
".venv*",
"build",
"dist",
"docker",
"docs/*",
"doctests/*",
"tasks.py",
"venv*",
"whitelist.py",
]

[tool.ruff.lint]
ignore = [
"E501", # line too long (taken care of with ruff format)
"E741", # ambiguous variable name
"N818", # Errors should have Error suffix
]

select = [
"E",
"F",
"FLY",
"I",
"N",
"W",
]

[tool.ruff.lint.per-file-ignores]
"redis/commands/bf/*" = [
# the `bf` module uses star imports, so this is required there.
"F405", # name may be undefined, or defined from star imports
]
"redis/commands/{bf,timeseries,json,search}/*" = [
"N",
]
"tests/*" = [
"I", # TODO: could be enabled, plenty of changes
"N801", # class name should use CapWords convention
"N803", # argument name should be lowercase
"N802", # function name should be lowercase
"N806", # variable name should be lowercase
]
4 changes: 2 additions & 2 deletions redis/_parsers/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
from .encoders import Encoder
from .socket import SERVER_CLOSED_CONNECTION_ERROR, SocketBuffer

MODULE_LOAD_ERROR = "Error loading the extension. " "Please check the server logs."
MODULE_LOAD_ERROR = "Error loading the extension. Please check the server logs."
NO_SUCH_MODULE_ERROR = "Error unloading module: no such module with that name"
MODULE_UNLOAD_NOT_POSSIBLE_ERROR = "Error unloading module: operation not " "possible."
MODULE_UNLOAD_NOT_POSSIBLE_ERROR = "Error unloading module: operation not possible."
MODULE_EXPORTS_DATA_TYPES_ERROR = (
"Error unloading module: the module "
"exports one or more module-side data "
Expand Down
6 changes: 2 additions & 4 deletions redis/asyncio/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -1154,9 +1154,7 @@ def get_node(
return self.nodes_cache.get(node_name)
else:
raise DataError(
"get_node requires one of the following: "
"1. node name "
"2. host and port"
"get_node requires one of the following: 1. node name 2. host and port"
)

def set_nodes(
Expand Down Expand Up @@ -1338,7 +1336,7 @@ async def initialize(self) -> None:
if len(disagreements) > 5:
raise RedisClusterException(
f"startup_nodes could not agree on a valid "
f'slots cache: {", ".join(disagreements)}'
f"slots cache: {', '.join(disagreements)}"
)

# Validate if all slots are covered or if we should try next startup node
Expand Down
2 changes: 1 addition & 1 deletion redis/asyncio/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -842,7 +842,7 @@ def __init__(
if cert_reqs is None:
self.cert_reqs = ssl.CERT_NONE
elif isinstance(cert_reqs, str):
CERT_REQS = {
CERT_REQS = { # noqa: N806
"none": ssl.CERT_NONE,
"optional": ssl.CERT_OPTIONAL,
"required": ssl.CERT_REQUIRED,
Expand Down
2 changes: 1 addition & 1 deletion redis/asyncio/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def from_url(url, **kwargs):
return Redis.from_url(url, **kwargs)


class pipeline:
class pipeline: # noqa: N801
def __init__(self, redis_obj: "Redis"):
self.p: "Pipeline" = redis_obj.pipeline()

Expand Down
1 change: 0 additions & 1 deletion redis/auth/token.py
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ def get_received_at_ms(self) -> float:


class JWToken(TokenInterface):

REQUIRED_FIELDS = {"exp"}

def __init__(self, token: str):
Expand Down
3 changes: 1 addition & 2 deletions redis/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -1514,8 +1514,7 @@ def raise_first_error(self, commands, response):
def annotate_exception(self, exception, number, command):
cmd = " ".join(map(safe_str, command))
msg = (
f"Command # {number} ({cmd}) of pipeline "
f"caused error: {exception.args[0]}"
f"Command # {number} ({cmd}) of pipeline caused error: {exception.args[0]}"
)
exception.args = (msg,) + exception.args[1:]

Expand Down
5 changes: 2 additions & 3 deletions redis/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -1628,7 +1628,7 @@ def initialize(self):
if len(disagreements) > 5:
raise RedisClusterException(
f"startup_nodes could not agree on a valid "
f'slots cache: {", ".join(disagreements)}'
f"slots cache: {', '.join(disagreements)}"
)

fully_covered = self.check_slots_coverage(tmp_slots)
Expand Down Expand Up @@ -2047,8 +2047,7 @@ def annotate_exception(self, exception, number, command):
"""
cmd = " ".join(map(safe_str, command))
msg = (
f"Command # {number} ({cmd}) of pipeline "
f"caused error: {exception.args[0]}"
f"Command # {number} ({cmd}) of pipeline caused error: {exception.args[0]}"
)
exception.args = (msg,) + exception.args[1:]

Expand Down
2 changes: 1 addition & 1 deletion redis/commands/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,7 +595,7 @@ def cluster_setslot(
"CLUSTER SETSLOT", slot_id, state, node_id, target_nodes=target_node
)
elif state.upper() == "STABLE":
raise RedisError('For "stable" state please use ' "cluster_setslot_stable")
raise RedisError('For "stable" state please use cluster_setslot_stable')
else:
raise RedisError(f"Invalid slot state: {state}")

Expand Down
7 changes: 4 additions & 3 deletions redis/commands/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3415,7 +3415,9 @@ def smembers(self, name: str) -> Union[Awaitable[Set], Set]:
"""
return self.execute_command("SMEMBERS", name, keys=[name])

def smismember(self, name: str, values: List, *args: List) -> Union[
def smismember(
self, name: str, values: List, *args: List
) -> Union[
Awaitable[List[Union[Literal[0], Literal[1]]]],
List[Union[Literal[0], Literal[1]]],
]:
Expand Down Expand Up @@ -4162,8 +4164,7 @@ def zadd(
raise DataError("ZADD allows either 'gt' or 'lt', not both")
if incr and len(mapping) != 1:
raise DataError(
"ZADD option 'incr' only works when passing a "
"single element/score pair"
"ZADD option 'incr' only works when passing a single element/score pair"
)
if nx and (gt or lt):
raise DataError("Only one of 'nx', 'lt', or 'gr' may be defined.")
Expand Down
4 changes: 1 addition & 3 deletions redis/commands/graph/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,9 +171,7 @@ def config(self, name, value=None, set=False):
if set:
params.append(value)
else:
raise DataError(
"``value`` can be provided only when ``set`` is True"
) # noqa
raise DataError("``value`` can be provided only when ``set`` is True") # noqa
return self.execute_command(CONFIG_CMD, *params)

def list_keys(self):
Expand Down
4 changes: 2 additions & 2 deletions redis/commands/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -138,9 +138,9 @@ def stringify_param_value(value):
elif value is None:
return "null"
elif isinstance(value, (list, tuple)):
return f'[{",".join(map(stringify_param_value, value))}]'
return f"[{','.join(map(stringify_param_value, value))}]"
elif isinstance(value, dict):
return f'{{{",".join(f"{k}:{stringify_param_value(v)}" for k, v in value.items())}}}' # noqa
return f"{{{','.join(f'{k}:{stringify_param_value(v)}' for k, v in value.items())}}}" # noqa
else:
return str(value)

Expand Down
6 changes: 2 additions & 4 deletions redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -622,9 +622,7 @@ def read_response(
except OSError as e:
if disconnect_on_error:
self.disconnect()
raise ConnectionError(
f"Error while reading from {host_error}" f" : {e.args}"
)
raise ConnectionError(f"Error while reading from {host_error} : {e.args}")
except BaseException:
# Also by default close in case of BaseException. A lot of code
# relies on this behaviour when doing Command/Response pairs.
Expand Down Expand Up @@ -1040,7 +1038,7 @@ def __init__(
if ssl_cert_reqs is None:
ssl_cert_reqs = ssl.CERT_NONE
elif isinstance(ssl_cert_reqs, str):
CERT_REQS = {
CERT_REQS = { # noqa: N806
"none": ssl.CERT_NONE,
"optional": ssl.CERT_OPTIONAL,
"required": ssl.CERT_REQUIRED,
Expand Down
3 changes: 3 additions & 0 deletions redis/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ class ModuleError(ResponseError):

class LockError(RedisError, ValueError):
"Errors acquiring or releasing a lock"

# NOTE: For backwards compatibility, this class derives from ValueError.
# This was originally chosen to behave like threading.Lock.

Expand All @@ -89,11 +90,13 @@ def __init__(self, message=None, lock_name=None):

class LockNotOwnedError(LockError):
"Error trying to extend or release a lock that is (no longer) owned"

pass


class ChildDeadlockedError(Exception):
"Error indicating that a child process is deadlocked after a fork()"

pass


Expand Down
3 changes: 2 additions & 1 deletion redis/ocsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
from cryptography.hazmat.primitives.hashes import SHA1, Hash
from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat
from cryptography.x509 import ocsp

from redis.exceptions import AuthorizationError, ConnectionError


Expand Down Expand Up @@ -56,7 +57,7 @@ def _check_certificate(issuer_cert, ocsp_bytes, validate=True):
if ocsp_response.response_status == ocsp.OCSPResponseStatus.SUCCESSFUL:
if ocsp_response.certificate_status != ocsp.OCSPCertStatus.GOOD:
raise ConnectionError(
f'Received an {str(ocsp_response.certificate_status).split(".")[1]} '
f"Received an {str(ocsp_response.certificate_status).split('.')[1]} "
"ocsp certificate status"
)
else:
Expand Down
2 changes: 1 addition & 1 deletion redis/sentinel.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ def __repr__(self):
)
return (
f"<{type(self).__module__}.{type(self).__name__}"
f'(sentinels=[{",".join(sentinel_addresses)}])>'
f"(sentinels=[{','.join(sentinel_addresses)}])>"
)

def check_master_state(self, state, service_name):
Expand Down
6 changes: 2 additions & 4 deletions tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ def build_docs(c):
@task
def linters(c):
"""Run code linters"""
run("flake8 tests redis")
run("black --target-version py37 --check --diff tests redis")
run("isort --check-only --diff tests redis")
run("ruff check tests redis")
run("ruff format --check --diff tests redis")
run("vulture redis whitelist.py --min-confidence 80")
run("flynt --fail-on-change --dry-run tests redis")


@task
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ def wait_for_command(client, monitor, command, key=None):
if Version(redis_version) >= Version("5.0.0"):
id_str = str(client.client_id())
else:
id_str = f"{random.randrange(2 ** 32):08x}"
id_str = f"{random.randrange(2**32):08x}"
key = f"__REDIS-PY-{id_str}__"
client.get(key)
while True:
Expand Down
2 changes: 1 addition & 1 deletion tests/test_asyncio/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ async def wait_for_command(
if Version(redis_version) >= Version("5.0.0"):
id_str = str(await client.client_id())
else:
id_str = f"{random.randrange(2 ** 32):08x}"
id_str = f"{random.randrange(2**32):08x}"
key = f"__REDIS-PY-{id_str}__"
await client.get(key)
while True:
Expand Down
Loading
Loading