Skip to content

analyze graph: resolve string imports that reference attributes, not just modules#24058

Merged
MichaReiser merged 3 commits intoastral-sh:mainfrom
markjm:markjm/pydoc
Mar 23, 2026
Merged

analyze graph: resolve string imports that reference attributes, not just modules#24058
MichaReiser merged 3 commits intoastral-sh:mainfrom
markjm:markjm/pydoc

Conversation

@markjm
Copy link
Copy Markdown
Contributor

@markjm markjm commented Mar 19, 2026

Problem Statement

When detect-string-imports is enabled, strings like "a.b.c.MyClass" are dropped because a/b/c/MyClass.py doesn't exist.

One common pattern (for better or worse) we have in our codebase is a fully-specified import-like string to an attribute in a module. We specifically use pydoc.locate() for this resolution, so the proposal here is for analyze graph to also see these types of string "imports".

Proposed Fix

The change is pretty simple - just allow the resolver to try progressively shorter prefixes only for string imports

eg. a.b.c, then a.b, etc. — until one resolves to an actual module file.

The fallback respects min-dots so it never produces a candidate with fewer dots than the configured threshold.

I could imagine some edge-cases I am not thinking about, so open to suggestions. For example, maybe just always only check n-1 (so only support top-level attributes in a module)

Test Plan

Added relevant tests for this behaviour and verified this change does solve my problem in my repo!

…t just modules

When `detect-string-imports` is enabled, strings like `"a.b.c.MyClass"` were dropped because `a/b/c/MyClass.py` doesn't exist.

One common pattern (for better or worse) we have in our codebase is a fully-spcified import-like string to an *attribute* in a module.

We specifically use [`pydoc.locate()`](https://github.com/python/cpython/blob/3.14/Lib/pydoc.py#L1719) for this resolution, so the proposal here is for `analyze graph` to also see these types of string "imports".

The change is pretty simple - just allow the resolver to try progressively shorter prefixes **only for string imports**

eg. `a.b.c`, then `a.b`, etc. — until one resolves to an actual module file.

The fallback respects `min-dots` so it never produces a candidate with fewer dots than the configured threshold.

I could imagine some edge-cases I am not thinking about, so open to suggestions. For example, maybe just always only check `n-1` (so only support top-level attributes in a module)
@MichaReiser MichaReiser added the analyze Related to Ruff analyze functionality label Mar 20, 2026
@MichaReiser MichaReiser enabled auto-merge (squash) March 23, 2026 08:58
@MichaReiser MichaReiser merged commit 0ed93d2 into astral-sh:main Mar 23, 2026
41 checks passed
carljm added a commit that referenced this pull request Mar 25, 2026
* main: (36 commits)
  [ty] Reduce diagnostic range for `invalid-metaclass` (#24145)
  [ty] Simplify TypeVar assignability/subtyping logic (#24138)
  [ty] Prevent tainted loop bindings in cycle normalization (#24143)
  [ty] Add precisely-typed overloads for `TypedDict` update (#24101)
  [ty] Fix folding ranges of comments separated by statements (#24132)
  Bump ecosystem-analyzer pin (#24136)
  Bump ecosystem-analyzer pin (#24135)
  Simplify `NewType` handling in `relation.rs` (#24109)
  [ty] Add more tests for `NewType` subtyping (#24115)
  [ty] Add `NewType`s to the property tests (#24113)
  [ty] Prepare test files for unreachable code change (#24133)
  `analyze graph`: resolve string imports that reference attributes, not just modules (#24058)
  Update Artifact GitHub Actions dependencies (#24116)
  Update taiki-e/install-action action to v2.68.33 (#24130)
  Update taiki-e/install-action action to v2.68.32 (#24123)
  Update Rust crate serde_with to v3.18.0 (#24126)
  Update Swatinem/rust-cache action to v2.9.1 (#24127)
  Update Rust crate quick-junit to 0.6.0 (#24125)
  Update Rust crate clap to v4.6.0 (#24124)
  Update Rust crate tracing-subscriber to v0.3.23 (#24122)
  ...
nicopauss pushed a commit to Intersec/lib-common that referenced this pull request Apr 1, 2026
##### [\`v0.15.8\`](https://github.com/astral-sh/ruff/blob/HEAD/CHANGELOG.md#0158)

Released on 2026-03-26.

##### Preview features

- \[`ruff`] New rule `unnecessary-if` (`RUF050`) ([#24114](astral-sh/ruff#24114))
- \[`ruff`] New rule `useless-finally` (`RUF072`) ([#24165](astral-sh/ruff#24165))
- \[`ruff`] New rule `f-string-percent-format` (`RUF073`): warn when using `%` operator on an f-string ([#24162](astral-sh/ruff#24162))
- \[`pyflakes`] Recognize `frozendict` as a builtin for Python 3.15+ ([#24100](astral-sh/ruff#24100))

##### Bug fixes

- \[`flake8-async`] Use fully-qualified `anyio.lowlevel` import in autofix (`ASYNC115`) ([#24166](astral-sh/ruff#24166))
- \[`flake8-bandit`] Check tuple arguments for partial paths in `S607` ([#24080](astral-sh/ruff#24080))
- \[`pyflakes`] Skip `undefined-name` (`F821`) for conditionally deleted variables ([#24088](astral-sh/ruff#24088))
- `E501`/`W505`/formatter: Exclude nested pragma comments from line width calculation ([#24071](astral-sh/ruff#24071))
- Fix `%foo?` parsing in IPython assignment expressions ([#24152](astral-sh/ruff#24152))
- `analyze graph`: resolve string imports that reference attributes, not just modules ([#24058](astral-sh/ruff#24058))

##### Rule changes

- \[`eradicate`] ignore `ty: ignore` comments in `ERA001` ([#24192](astral-sh/ruff#24192))
- \[`flake8-bandit`] Treat `sys.executable` as trusted input in `S603` ([#24106](astral-sh/ruff#24106))
- \[`flake8-self`] Recognize `Self` annotation and `self` assignment in `SLF001` ([#24144](astral-sh/ruff#24144))
- \[`pyflakes`] `F507`: Fix false negative for non-tuple RHS in `%`-formatting ([#24142](astral-sh/ruff#24142))
- \[`refurb`] Parenthesize generator arguments in `FURB142` fixer ([#24200](astral-sh/ruff#24200))

##### Performance

- Speed up diagnostic rendering ([#24146](astral-sh/ruff#24146))

##### Server

- Warn when Markdown files are skipped due to preview being disabled ([#24150](astral-sh/ruff#24150))

##### Documentation

- Clarify `extend-ignore` and `extend-select` settings documentation ([#24064](astral-sh/ruff#24064))
- Mention AI policy in PR template ([#24198](astral-sh/ruff#24198))

##### Other changes

- Use trusted publishing for NPM packages ([#24171](astral-sh/ruff#24171))

##### Contributors

- [@bitloi](https://github.com/bitloi)
- [@Sim-hu](https://github.com/Sim-hu)
- [@mvanhorn](https://github.com/mvanhorn)
- [@chinar-amrutkar](https://github.com/chinar-amrutkar)
- [@markjm](https://github.com/markjm)
- [@RenzoMXD](https://github.com/RenzoMXD)
- [@vivekkhimani](https://github.com/vivekkhimani)
- [@seroperson](https://github.com/seroperson)
- [@moktamd](https://github.com/moktamd)
- [@charliermarsh](https://github.com/charliermarsh)
- [@ntBre](https://github.com/ntBre)
- [@zanieb](https://github.com/zanieb)
- [@dylwil3](https://github.com/dylwil3)
- [@MichaReiser](https://github.com/MichaReiser)

Renovate-Branch: renovate/2024.6-ruff-0.15.x
Change-Id: Ifd4216a963962ffb24a4df69802bc60fcc29628d
Priv-Id: 46d2f61be3a5e65a9fdd2fef998ba41ea3388f12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

analyze Related to Ruff analyze functionality

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants