diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0198a67c5e..4209dcf8d6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -44,7 +44,7 @@ repos: name: "run black in all files" - repo: https://github.com/charliermarsh/ruff-pre-commit - rev: v0.3.4 + rev: v0.8.0 hooks: - id: ruff args: [--fix, --fixable=I] diff --git a/disnake/app_commands.py b/disnake/app_commands.py index 727f35cb93..1da2b8576f 100644 --- a/disnake/app_commands.py +++ b/disnake/app_commands.py @@ -465,7 +465,7 @@ def localize(self, store: LocalizationProtocol) -> None: o.localize(store) -class ApplicationCommand(ABC): +class ApplicationCommand(ABC): # noqa: B024 # this will get refactored eventually """The base class for application commands. The following classes implement this ABC: diff --git a/disnake/ext/commands/converter.py b/disnake/ext/commands/converter.py index 422416fd33..79570b9f8e 100644 --- a/disnake/ext/commands/converter.py +++ b/disnake/ext/commands/converter.py @@ -1187,7 +1187,7 @@ def get_converter(param: inspect.Parameter) -> Any: def is_generic_type(tp: Any, *, _GenericAlias: Type = _GenericAlias) -> bool: - return isinstance(tp, type) and issubclass(tp, Generic) or isinstance(tp, _GenericAlias) + return (isinstance(tp, type) and issubclass(tp, Generic)) or isinstance(tp, _GenericAlias) CONVERTER_MAPPING: Dict[Type[Any], Type[Converter]] = { diff --git a/disnake/ext/commands/params.py b/disnake/ext/commands/params.py index e472c1ae13..e7df5f543d 100644 --- a/disnake/ext/commands/params.py +++ b/disnake/ext/commands/params.py @@ -804,7 +804,7 @@ def parse_parameter(self, param: inspect.Parameter) -> None: self.param_name = param.name def parse_doc(self, doc: disnake.utils._DocstringParam) -> None: - if self.type == str and doc["type"] is not None: + if self.type is str and doc["type"] is not None: self.parse_annotation(doc["type"]) self.description = self.description or doc["description"] diff --git a/disnake/ext/tasks/__init__.py b/disnake/ext/tasks/__init__.py index 6532c3d088..95ff023330 100644 --- a/disnake/ext/tasks/__init__.py +++ b/disnake/ext/tasks/__init__.py @@ -275,7 +275,7 @@ def next_iteration(self) -> Optional[datetime.datetime]: """ if self._task is MISSING: return None - elif self._task and self._task.done() or self._stop_next_iteration: + elif (self._task and self._task.done()) or self._stop_next_iteration: return None return self._next_iteration diff --git a/disnake/interactions/base.py b/disnake/interactions/base.py index 585406ed41..09795285d4 100644 --- a/disnake/interactions/base.py +++ b/disnake/interactions/base.py @@ -223,11 +223,10 @@ def __init__(self, *, data: InteractionPayload, state: ConnectionState) -> None: self.author = ( isinstance(guild_fallback, Guild) and guild_fallback.get_member(int(member["user"]["id"])) - or Member( - state=self._state, - guild=guild_fallback, # type: ignore # may be `Object` - data=member, - ) + ) or Member( + state=self._state, + guild=guild_fallback, # type: ignore # may be `Object` + data=member, ) self._permissions = int(member.get("permissions", 0)) elif user := data.get("user"): @@ -1915,15 +1914,11 @@ def __init__( user_id = int(str_id) member = members.get(str_id) if member is not None: - self.members[user_id] = ( - guild - and guild.get_member(user_id) - or Member( - data=member, - user_data=user, - guild=guild_fallback, # type: ignore - state=state, - ) + self.members[user_id] = (guild and guild.get_member(user_id)) or Member( + data=member, + user_data=user, + guild=guild_fallback, # type: ignore + state=state, ) else: self.users[user_id] = User(state=state, data=user) diff --git a/disnake/state.py b/disnake/state.py index c3263976c6..bb9b99a874 100644 --- a/disnake/state.py +++ b/disnake/state.py @@ -458,7 +458,7 @@ def _add_global_application_command( /, ) -> None: if not application_command.id: - AssertionError("The provided application command does not have an ID") + raise AssertionError("The provided application command does not have an ID") self._global_application_commands[application_command.id] = application_command def _remove_global_application_command(self, application_command_id: int, /) -> None: @@ -478,7 +478,7 @@ def _add_guild_application_command( self, guild_id: int, application_command: APIApplicationCommand ) -> None: if not application_command.id: - AssertionError("The provided application command does not have an ID") + raise AssertionError("The provided application command does not have an ID") try: granula = self._guild_application_commands[guild_id] granula[application_command.id] = application_command @@ -2100,14 +2100,10 @@ def _get_partial_interaction_channel( # the factory can't be a DMChannel or GroupChannel here data.setdefault("position", 0) # type: ignore - return ( - isinstance(guild, Guild) - and guild.get_channel_or_thread(channel_id) - or factory( - guild=guild, # type: ignore # FIXME: create proper fallback guild instead of passing Object - state=self, - data=data, # type: ignore # generic payload type - ) + return (isinstance(guild, Guild) and guild.get_channel_or_thread(channel_id)) or factory( + guild=guild, # type: ignore # FIXME: create proper fallback guild instead of passing Object + state=self, + data=data, # type: ignore # generic payload type ) def get_channel(self, id: Optional[int]) -> Optional[Union[Channel, Thread]]: diff --git a/disnake/utils.py b/disnake/utils.py index 9061cd0f61..07754afafc 100644 --- a/disnake/utils.py +++ b/disnake/utils.py @@ -1158,7 +1158,7 @@ def evaluate_annotation( return cache[tp] # this is how annotations are supposed to be unstringifed - evaluated = eval(tp, globals, locals) # noqa: PGH001, S307 + evaluated = eval(tp, globals, locals) # noqa: S307 # recurse to resolve nested args further evaluated = evaluate_annotation(evaluated, globals, locals, cache) diff --git a/pyproject.toml b/pyproject.toml index 9bab9ae822..ed9467bfec 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -71,7 +71,7 @@ tools = [ "slotscheck~=0.16.4", "python-dotenv~=1.0.0", "check-manifest==0.49", - "ruff==0.3.4", + "ruff==0.8.0", ] changelog = [ "towncrier==23.6.0", @@ -149,7 +149,7 @@ select = [ # "RET", # flake8-return # "SIM", # flake8-simplify "TID251", # flake8-tidy-imports, replaces S404 - "TCH", # flake8-type-checking + "TC", # flake8-type-checking "RUF", # ruff specific exceptions "PT", # flake8-pytest-style "Q", # flake8-quotes @@ -178,6 +178,10 @@ ignore = [ "RUF005", # might not be actually faster "RUF006", # might not be an issue/very extreme cases + # we keep __all__ and __slots__ (roughly) sorted by source, not alphabetically + "RUF022", + "RUF023", + # calling subprocess with dynamic arguments is generally fine, the only way to avoid this is ignoring it "S603", @@ -202,9 +206,9 @@ ignore = [ # ignore imports that could be moved into type-checking blocks # (no real advantage other than possibly avoiding cycles, # but can be dangerous in places where we need to parse signatures) - "TCH001", - "TCH002", - "TCH003", + "TC001", + "TC002", + "TC003", "S311", # insecure RNG usage, we don't use these for security-related things "PLE0237", # pyright seems to catch this already @@ -259,6 +263,13 @@ mark-parentheses = false [tool.ruff.lint.flake8-tidy-imports.banned-api] "subprocess".msg = "Consider possible security implications associated with the subprocess module." # replaces S404 +[tool.ruff.lint.flake8-bugbear] +extend-immutable-calls = [ + # this is immutable, except for storing locks, which are fine to share across contexts + "disnake.webhook.async_.AsyncWebhookAdapter", +] + + [tool.towncrier] template = "changelog/_template.rst.jinja" package = "disnake" diff --git a/tests/ext/commands/test_params.py b/tests/ext/commands/test_params.py index 96f2c08c32..fdfaa59002 100644 --- a/tests/ext/commands/test_params.py +++ b/tests/ext/commands/test_params.py @@ -140,10 +140,10 @@ def test_nan(self, value) -> None: def test_valid(self) -> None: x: Any = commands.Range[int, -1, 2] - assert x.underlying_type == int + assert x.underlying_type is int x: Any = commands.Range[float, ..., 23.45] - assert x.underlying_type == float + assert x.underlying_type is float class TestString: @@ -211,7 +211,7 @@ def test_optional(self, annotation_str) -> None: assert info.min_value == 1 assert info.max_value == 2 - assert info.type == int + assert info.type is int class TestIsolateSelf: