Skip to content

Conversation

amyreese
Copy link
Contributor

Summary

Adds new rule to find and report use of httpx.Client in synchronous
functions.

See issue #8451

Test Plan

New snapshots for ASYNC212.py with cargo insta test.

Adds new rule to find and report use of `httpx.Client` in synchronous
functions.
@amyreese
Copy link
Contributor Author

Still needs some work (and learning) to catch usage of httpx.Client methods, not just instantiation.

Copy link
Contributor

github-actions bot commented Aug 26, 2025

ruff-ecosystem results

Linter (stable)

✅ ecosystem check detected no linter changes.

Linter (preview)

✅ ecosystem check detected no linter changes.


async def foo():
client: httpx.Client = ...
client.request() # ASYNC212
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This one still isn't caught, presumably because the TypeChecker bits only capture annotations at the function level?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should work. I played around a bit with the PTH210 rule, which uses the PathlibPathChecker, and it will detect both module-level and function-level bindings like this:

def foo():
    path: Path = ...
    path.with_suffix(".")

I'm wondering if the union traversal might be disrupting this check.

@amyreese amyreese marked this pull request as ready for review August 27, 2025 00:24
@ntBre ntBre added the rule Implementing or modifying a lint rule label Aug 27, 2025
Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks great, thank you! I just had a couple of small suggestions and some ideas about the union handling that might help with the simple annotation case.


async def foo():
client: httpx.Client = ...
client.request() # ASYNC212
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should work. I played around a bit with the PTH210 rule, which uses the PathlibPathChecker, and it will detect both module-level and function-level bindings like this:

def foo():
    path: Path = ...
    path.with_suffix(".")

I'm wondering if the union traversal might be disrupting this check.

Comment on lines +127 to +128
49 | async def foo(client: httpx.Client | None):
50 | client.request() # ASYNC212
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah okay, this doesn't work for PTH210. I understand the traverse_union call now. I'd probably lean toward not traversing unions and matching our other type inference calls, but I don't feel too strongly if you think this is an important use case. We could also consider making a more general change to our TypeChecker code if this would always be helpful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was doing this mostly to match behavior with the upstream ASYNC212 implementation, which explicitly includes these unions/optionals in its test cases.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense! If we can handle both this and the regular annotation case, it's great to handle both. We can punt on trying to update any other TypeCheckers for now too.

Copy link
Contributor

@ntBre ntBre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thanks!

Would you mind updating the title to:

[flake8-async] Implement blocking-http-call-httpx (ASYNC212)

(just wrapping the linter name and rule code in backticks)

We pull the PR titles for changelog entries, and that's how we usually stylize them.

Other than that, feel free to merge whenever you're ready!

@ntBre ntBre added the preview Related to preview mode features label Aug 27, 2025
@amyreese amyreese changed the title [flake8-async] Implement blocking-http-call-httpx (ASYNC212) [flake8-async] Implement blocking-http-call-httpx (ASYNC212) Aug 27, 2025
@amyreese amyreese merged commit af259fa into astral-sh:main Aug 27, 2025
36 checks passed
@amyreese amyreese deleted the async212 branch August 28, 2025 16:56
dcreager added a commit that referenced this pull request Aug 28, 2025
* main:
  Fix mdtest ignore python code blocks (#20139)
  [ty] add support for cyclic legacy generic protocols (#20125)
  [ty] add cycle detection for find_legacy_typevars (#20124)
  Use new diff rendering format in tests (#20101)
  [ty] Fix 'too many cycle iterations' for unions of literals (#20137)
  [ty] No boundness analysis for implicit instance attributes (#20128)
  Bump 0.12.11 (#20136)
  [ty] Benchmarks for problematic implicit instance attributes cases (#20133)
  [`pyflakes`] Fix `allowed-unused-imports` matching for top-level modules (`F401`) (#20115)
  Move GitLab output rendering to `ruff_db` (#20117)
  [ty] Evaluate reachability of non-definitely-bound to Ambiguous (#19579)
  [ty] Introduce a representation for the top/bottom materialization of an invariant generic (#20076)
  [`flake8-async`] Implement `blocking-http-call-httpx` (`ASYNC212`) (#20091)
  [ty] print diagnostics with fully qualified name to disambiguate some cases (#19850)
  [`ruff`] Preserve relative whitespace in multi-line expressions (`RUF033`) (#19647)
second-ed pushed a commit to second-ed/ruff that referenced this pull request Sep 9, 2025
…stral-sh#20091)

## Summary

Adds new rule to find and report use of `httpx.Client` in synchronous
functions.

See issue astral-sh#8451

## Test Plan

New snapshots for `ASYNC212.py` with `cargo insta test`.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
preview Related to preview mode features rule Implementing or modifying a lint rule
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants