Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions docs/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog

`CalVer, YY.month.patch <https://calver.org/>`_

25.5.3
======
- :ref:`ASYNC115 <async115>` and :ref:`ASYNC116 <async116>` now also checks kwargs.

25.5.2
======
- :ref:`ASYNC102 <async102>` and :ref:`ASYNC120 <async120>` no longer requires cancel scopes to have a timeout. `(issue #272) <https://github.com/python-trio/flake8-async/issues/272>`_
Expand Down
2 changes: 1 addition & 1 deletion docs/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ adding the following to your ``.pre-commit-config.yaml``:
minimum_pre_commit_version: '2.9.0'
repos:
- repo: https://github.com/python-trio/flake8-async
rev: 25.5.2
rev: 25.5.3
hooks:
- id: flake8-async
# args: ["--enable=ASYNC100,ASYNC112", "--disable=", "--autofix=ASYNC"]
Expand Down
2 changes: 1 addition & 1 deletion flake8_async/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@


# CalVer: YY.month.patch, e.g. first release of July 2022 == "22.7.1"
__version__ = "25.5.2"
__version__ = "25.5.3"


# taken from https://github.com/Zac-HD/shed
Expand Down
67 changes: 40 additions & 27 deletions flake8_async/visitors/visitors.py
Original file line number Diff line number Diff line change
Expand Up @@ -305,11 +305,16 @@ class Visitor115(Flake8AsyncVisitor):
}

def visit_Call(self, node: ast.Call):
if not (m := get_matching_call(node, "sleep")):
return
if (
(m := get_matching_call(node, "sleep"))
and len(node.args) == 1
len(node.args) == 1
and isinstance(node.args[0], ast.Constant)
and node.args[0].value == 0
) or (
len(node.keywords) == 1
and isinstance(node.keywords[0].value, ast.Constant)
and node.keywords[0].value.value == 0
):
self.error(node, m.base)

Expand All @@ -324,32 +329,40 @@ class Visitor116(Flake8AsyncVisitor):
}

def visit_Call(self, node: ast.Call):
if (m := get_matching_call(node, "sleep")) and len(node.args) == 1:
if not (m := get_matching_call(node, "sleep")):
return
if len(node.args) == 1:
arg = node.args[0]
if (
# `trio.sleep(math.inf)`
(isinstance(arg, ast.Attribute) and arg.attr == "inf")
# `trio.sleep(inf)`
or (isinstance(arg, ast.Name) and arg.id == "inf")
# `trio.sleep(float("inf"))`
or (
isinstance(arg, ast.Call)
and isinstance(arg.func, ast.Name)
and arg.func.id == "float"
and len(arg.args)
and isinstance(arg.args[0], ast.Constant)
and arg.args[0].value == "inf"
)
# `trio.sleep(1e999)` (constant value inf)
# `trio.sleep(86401)`
# `trio.sleep(86400.1)`
or (
isinstance(arg, ast.Constant)
and isinstance(arg.value, (int, float))
and arg.value > 86400
)
):
self.error(node, m.base)
elif len(node.keywords) == 1:
arg = node.keywords[0].value
else:
# invalid call, not our problem
return

if (
# `trio.sleep(math.inf)`
(isinstance(arg, ast.Attribute) and arg.attr == "inf")
# `trio.sleep(inf)`
or (isinstance(arg, ast.Name) and arg.id == "inf")
# `trio.sleep(float("inf"))`
or (
isinstance(arg, ast.Call)
and isinstance(arg.func, ast.Name)
and arg.func.id == "float"
and len(arg.args)
and isinstance(arg.args[0], ast.Constant)
and arg.args[0].value == "inf"
)
# `trio.sleep(1e999)` (constant value inf)
# `trio.sleep(86401)`
# `trio.sleep(86400.1)`
or (
isinstance(arg, ast.Constant)
and isinstance(arg.value, (int, float))
and arg.value > 86400
)
):
self.error(node, m.base)


@error_class
Expand Down
13 changes: 13 additions & 0 deletions tests/eval_files/async115.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ async def afoo():
time.sleep(0)
sleep(0)

# in trio it's called 'seconds', in anyio it's 'delay', but
# we don't care about the kwarg name. #382
await trio.sleep(seconds=0) # error: 10, "trio"
await trio.sleep(delay=0) # error: 10, "trio"
await trio.sleep(anything=0) # error: 10, "trio"

await trio.sleep(seconds=1)

await trio.sleep()

# we don't care to suppress this
await trio.sleep(0, seconds=1) # error: 10, "trio"


# don't require being inside a function
trio.sleep(0) # error: 0, "trio"
Expand Down
6 changes: 6 additions & 0 deletions tests/eval_files/async116.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,12 @@ async def foo():
await trio.sleep(inf.inf) # error: 10, "trio"
await trio.sleep(inf.anything)

# in trio the kwarg name is 'seconds', in anyio it's 'delay', but
# we error regardless of what it is. #382
await trio.sleep(seconds=inf) # error: 10, "trio"
await trio.sleep(delay=inf) # error: 10, "trio"
await trio.sleep(anything=inf) # error: 10, "trio"


# does not require the call to be awaited, nor in an async fun
trio.sleep(86401) # error: 0, "trio"
Expand Down
Loading