Skip to content

chore(deps): bump pyan3 from 2.4.0 to 2.6.1#232

Merged
squid-protocol merged 1 commit into
mainfrom
dependabot/pip/pyan3-2.6.1
Jul 17, 2026
Merged

chore(deps): bump pyan3 from 2.4.0 to 2.6.1#232
squid-protocol merged 1 commit into
mainfrom
dependabot/pip/pyan3-2.6.1

Conversation

@dependabot

@dependabot dependabot Bot commented on behalf of github Jul 17, 2026

Copy link
Copy Markdown
Contributor

Bumps pyan3 from 2.4.0 to 2.6.1.

Release notes

Sourced from pyan3's releases.

v2.6.1

Hotfix release.

Fixed

  • Wildcard expansion no longer invents false edges to same-named definitions in the same module. An attribute call on an imported-but-unanalyzed module (e.g. othermod.cache()) fell back to a *.cache wildcard, which expand_unknowns then bound to any same-named definition whose module counts as imported — and since a module always "imports" itself, it wired a spurious edge to a local cache(). Expansion now fires only when the name actually appears as a bare reference in the source scope, so attribute accesses no longer leak into unrelated same-name functions. (#134)

v2.6.0 — Cadastre

New features

  • Module-level name bindings now produce graph Nodes. Every module-level assignment (e.g. CONSTANT = 42, LOGGER = logging.getLogger(__name__), store = _NS()) creates a defined Flavor.NAME Node at the bound dotted path. from mymod import x now resolves to the actual binding instead of contracting to a wildcard, and the #127 attribute-fallback lands on the specific binding rather than climbing all the way to the enclosing module. Function-locals are unchanged — they stay as scope-only bindings to keep the graph readable. Edgeless NAME Nodes (module constants nobody imports) are suppressed from the rendered output by default; they remain in the analyzer's graph for cross-module resolution.
  • Namespace-style modules now resolve attribute access to the kwarg's target. When the rhs of a binding is Call(func=...) whose resolved import origin is in the built-in registry (unpythonic.env.env, top-level re-export unpythonic.env, types.SimpleNamespace, argparse.Namespace), the LHS is upgraded to Flavor.NAMESPACE_OBJECT and its scope is populated with the call's keyword arguments. External config.thingy resolves directly to whatever was passed as thingy=, bypassing the #127 module-level fallback. Recognised at all four binding sites: config = env(...), config: Env = env(...), walrus (config := env(...)), and with env(...) as config:. Staged form config = env(); config.a = baa is also covered (later attribute writes populate the namespace's scope through the existing set_attribute machinery). setattr(config, name, value) writes are recognised when name is a string literal, a name bound to a string literal in any scope reachable from the call site, or an imported name resolving to a string literal in another module. (#129)
  • --namespace-constructor FQN registers an extra namespace-constructor beyond the built-in registry (e.g. --namespace-constructor mylib.MyNamespace). Repeatable, or comma-separated. Threaded through to the create_callgraph API as namespace_constructors=[...]. Supplying the option emits a one-shot stderr nudge inviting the user to file an issue if their constructor is reasonably common, so the built-in registry can grow from observed real-world use. (#129)

Bug fixes

  • Cross-module attribute reads on namespace-style modules now produce uses edges. A module whose public surface is a runtime-built object (SimpleNamespace, unpythonic.env.env, a small class _NS: pass; store = _NS() shim) used to appear as an isolated node even when it was central to the subsystem — every store.dataset access landed on a synthetic ATTRIBUTE node that visgraph dropped as undefined. The analyzer now also emits an edge to the immediate defined parent of the obj (typically the exporting module) when the attribute itself can't be resolved. Symmetric for attribute writes (store.flag = value). One-level only — does not climb through unanalyzed packages, and within-scope self-references are suppressed (a method reading an undefined attribute on its own class, or a function reading module-level state in its own module, is just normal scoping). Generalizes the existing class-fallback (Enum members, class constants) introduced in 2.4.0. (#127)
  • Advisory when infer_root may have misidentified the package root. Two ambiguous situations now emit a warning suggesting --root: (1) inference walked up at least one package level and stopped at a directory that has neither __init__.py nor a project-root marker (pyproject.toml, setup.py, setup.cfg) — consistent with a top-level PEP 420 namespace package; (2) inference didn't walk up at all but the input directory's parent has __init__.py — consistent with the user feeding pyan the contents of a namespace subpackage (e.g. pyan3 pkg/sub_ns/*.py where sub_ns/ has no __init__.py), which would otherwise silently produce bare module names and broken relative imports. Auto-walking further is unsafe — the same filesystem shapes also occur for workspace directories like tests/ or examples/ — so the choice is left to the user. The --root help text now also mentions the namespace-package case explicitly. (#128)

Internal

  • analyzer.py decomposed. Graph state and post-analysis query API extracted to pyan.callgraph; postprocessing pipeline to pyan.postprocessor; NAMESPACE_OBJECT pattern recognizers to pyan.recognizers. Public API (create_callgraph, create_modulegraph, main) unchanged.
  • Test suite reorganised. test_features.py split into per-concern files (test_classes.py, test_functions.py, test_iteration.py, test_async_context.py, test_match.py, test_assignments.py, test_imports.py, test_type_params.py, test_misc.py).
  • Flavor rename: Flavor.NAMESPACE (synthetic structural marker for module/class/function scope bookkeeping) is now Flavor.SCOPE. The new Flavor.NAMESPACE_OBJECT represents a runtime namespace value (an env instance, a SimpleNamespace instance) — a NAME with a populated scope listing its statically-visible attributes. The Node represents the scope; the Scope class implements one — same concept at two layers.

v2.5.0 — Legend

New features

  • Wildcard imports now resolve to actual targets. from pkg import * is desugared at analysis time against the target package's __all__ when declared as a literal list/tuple of strings, and against the public-names rule (every module-scope name not starting with _) otherwise. Names reached via wildcard — including those re-exported through __init__.py — now appear as concrete edges in the call graph instead of as spurious *.* residue at the importer's module level. Non-literal __all__ forms (augmented assignment, dynamic construction) fall back to the public-names rule with a debug log. (#126)

Internal

  • Prescan phase added before the two visitor passes. CallGraphVisitor.process now does a lightweight scope + __all__ walk over every input file up front, so cross-module metadata is fully populated before pass 1. This makes wildcard desugaring order-independent — the consumer of a wildcard import no longer has to appear after the exporting package in the filename list.

v2.4.3

Bug fixes

  • Names referenced inside a decorator's arguments are now attributed to the decorated function, not only to the enclosing module. Previously, a function decorated with e.g. @app.get("/x", dependencies=[Depends(Guard())]) showed no uses of Depends or Guard — those edges landed on the module instead. The function now also gets a uses edge to each target referenced in its decorator arguments, mirroring the existing treatment of default values. (#125 — thanks @​doctorgu)
  • Class decorators are now analyzed — previously visit_ClassDef ignored decorator_list entirely, so @dataclass or @register(kind="x") on a class produced no uses edges anywhere. Class decorators now behave like function decorators: the decorator expression is visited at module scope, and referenced names are also attributed to the decorated class.

v2.4.2 — Benchmark

A surveyor's benchmark is a reference mark — a fixed point of known position, cut into rock, that everything else can be measured against. This release is exactly that: no new user-visible features, but the Sphinx extension is now covered by an end-to-end integration test, so what was previously advertised is now verified.

Thanks to @​BlocksecPHD for contributing the test (#124, closes #114).

Internal

  • Build system migrated from hatchling+uv to PDM (pdm-backend). No user-visible changes; pip install pyan3 works as before.
  • Sphinx extension: end-to-end integration test covering sphinx-build, the .. callgraph:: directive, pan/zoom HTML wiring, and directive option propagation. Uses an in-test dot stub, so CI needs no system Graphviz. Closes #114. (#124 — thanks @​BlocksecPHD)

... (truncated)

Changelog

Sourced from pyan3's changelog.

2.6.1 (29 June 2026)

Fixed

  • Wildcard expansion no longer invents false edges to same-named definitions in the same module. An attribute call on an imported-but-unanalyzed module (e.g. othermod.cache()) fell back to a *.cache wildcard, which expand_unknowns then bound to any same-named definition whose module counts as imported — and since a module always "imports" itself, it wired a spurious edge to a local cache(). Expansion now fires only when the name actually appears as a bare reference in the source scope, so attribute accesses no longer leak into unrelated same-name functions. (#134)

2.6.0 (30 April 2026) — Cadastre

New features

  • Module-level name bindings now produce graph Nodes. Every module-level assignment (e.g. CONSTANT = 42, LOGGER = logging.getLogger(__name__), store = _NS()) creates a defined Flavor.NAME Node at the bound dotted path. from mymod import x now resolves to the actual binding instead of contracting to a wildcard, and the #127 attribute-fallback lands on the specific binding rather than climbing all the way to the enclosing module. Function-locals are unchanged — they stay as scope-only bindings to keep the graph readable. Edgeless NAME Nodes (module constants nobody imports) are suppressed from the rendered output by default; they remain in the analyzer's graph for cross-module resolution.
  • Namespace-style modules now resolve attribute access to the kwarg's target. When the rhs of a binding is Call(func=...) whose resolved import origin is in the built-in registry (unpythonic.env.env, top-level re-export unpythonic.env, types.SimpleNamespace, argparse.Namespace), the LHS is upgraded to Flavor.NAMESPACE_OBJECT and its scope is populated with the call's keyword arguments. External config.thingy resolves directly to whatever was passed as thingy=, bypassing the #127 module-level fallback. Recognised at all four binding sites: config = env(...), config: Env = env(...), walrus (config := env(...)), and with env(...) as config:. Staged form config = env(); config.a = baa is also covered (later attribute writes populate the namespace's scope through the existing set_attribute machinery). setattr(config, name, value) writes are recognised when name is a string literal, a name bound to a string literal in any scope reachable from the call site, or an imported name resolving to a string literal in another module. (#129)
  • --namespace-constructor FQN registers an extra namespace-constructor beyond the built-in registry (e.g. --namespace-constructor mylib.MyNamespace). Repeatable, or comma-separated. Threaded through to the create_callgraph API as namespace_constructors=[...]. Supplying the option emits a one-shot stderr nudge inviting the user to file an issue if their constructor is reasonably common, so the built-in registry can grow from observed real-world use. (#129)

Bug fixes

  • Cross-module attribute reads on namespace-style modules now produce uses edges. A module whose public surface is a runtime-built object (SimpleNamespace, unpythonic.env.env, a small class _NS: pass; store = _NS() shim) used to appear as an isolated node even when it was central to the subsystem — every store.dataset access landed on a synthetic ATTRIBUTE node that visgraph dropped as undefined. The analyzer now also emits an edge to the immediate defined parent of the obj (typically the exporting module) when the attribute itself can't be resolved. Symmetric for attribute writes (store.flag = value). One-level only — does not climb through unanalyzed packages, and within-scope self-references are suppressed (a method reading an undefined attribute on its own class, or a function reading module-level state in its own module, is just normal scoping). Generalizes the existing class-fallback (Enum members, class constants) introduced in 2.4.0. (#127)
  • Advisory when infer_root may have misidentified the package root. Two ambiguous situations now emit a warning suggesting --root: (1) inference walked up at least one package level and stopped at a directory that has neither __init__.py nor a project-root marker (pyproject.toml, setup.py, setup.cfg) — consistent with a top-level PEP 420 namespace package; (2) inference didn't walk up at all but the input directory's parent has __init__.py — consistent with the user feeding pyan the contents of a namespace subpackage (e.g. pyan3 pkg/sub_ns/*.py where sub_ns/ has no __init__.py), which would otherwise silently produce bare module names and broken relative imports. Auto-walking further is unsafe — the same filesystem shapes also occur for workspace directories like tests/ or examples/ — so the choice is left to the user. The --root help text now also mentions the namespace-package case explicitly. (#128)

Internal

  • analyzer.py decomposed. Graph state and post-analysis query API extracted to pyan.callgraph; postprocessing pipeline to pyan.postprocessor; NAMESPACE_OBJECT pattern recognizers to pyan.recognizers. Public API (create_callgraph, create_modulegraph, main) unchanged.
  • Test suite reorganised. test_features.py split into per-concern files (test_classes.py, test_functions.py, test_iteration.py, test_async_context.py, test_match.py, test_assignments.py, test_imports.py, test_type_params.py, test_misc.py).
  • Flavor rename: Flavor.NAMESPACE (synthetic structural marker for module/class/function scope bookkeeping) is now Flavor.SCOPE. The new Flavor.NAMESPACE_OBJECT represents a runtime namespace value (an env instance, a SimpleNamespace instance) — a NAME with a populated scope listing its statically-visible attributes. The Node represents the scope; the Scope class implements one — same concept at two layers.

2.5.0 (22 April 2026) — Legend

New features

  • Wildcard imports now resolve to actual targets. from pkg import * is desugared at analysis time against the target package's __all__ when declared as a literal list/tuple of strings, and against the public-names rule (every module-scope name not starting with _) otherwise. Names reached via wildcard — including those re-exported through __init__.py — now appear as concrete edges in the call graph instead of as spurious *.* residue at the importer's module level. Non-literal __all__ forms (augmented assignment, dynamic construction) fall back to the public-names rule with a debug log. (#126)

Internal

  • Prescan phase added before the two visitor passes. CallGraphVisitor.process now does a lightweight scope + __all__ walk over every input file up front, so cross-module metadata is fully populated before pass 1. This makes wildcard desugaring order-independent — the consumer of a wildcard import no longer has to appear after the exporting package in the filename list.

2.4.3 (20 April 2026)

Bug fixes

  • Names referenced inside a decorator's arguments are now attributed to the decorated function, not only to the enclosing module. Previously, a function decorated with e.g. @app.get("/x", dependencies=[Depends(Guard())]) showed no uses of Depends or Guard — those edges landed on the module instead. The function now also gets a uses edge to each target referenced in its decorator arguments, mirroring the existing treatment of default values. (#125 — thanks @​doctorgu)
  • Class decorators are now analyzed — previously visit_ClassDef ignored decorator_list entirely, so @dataclass or @register(kind="x") on a class produced no uses edges anywhere. Class decorators now behave like function decorators: the decorator expression is visited at module scope, and referenced names are also attributed to the decorated class.

... (truncated)

Commits
  • f2530da Release 2.6.1
  • 75a9f60 Document #134 fix in changelog; silence infer_root in its new test
  • 3da6b23 Merge pull request #135 from Morketh/fix-wildcard-expansion
  • 654e00e Bump actions/setup-python from 6.2.0 to 6.3.0 (#137)
  • d9aea16 Address review feedback
  • 5f6032f TODO_DEFERRED: note expand_unknowns dangling-wildcard architecture
  • 0777aa2 tests: pass explicit root to silence infer_root warnings
  • 93f2cb1 Bump actions/checkout from 6.0.3 to 7.0.0 (#136)
  • f639ae6 Fix expand_unknowns: only expand wildcards if name is in source scope
  • 550c405 ci: set least-privilege GITHUB_TOKEN permissions (#133)
  • Additional commits viewable in compare view

Dependabot compatibility score

Dependabot will resolve any conflicts with this PR as long as you don't alter it yourself. You can also trigger a rebase manually by commenting @dependabot rebase.


Dependabot commands and options

You can trigger Dependabot actions by commenting on this PR:

  • @dependabot rebase will rebase this PR
  • @dependabot recreate will recreate this PR, overwriting any edits that have been made to it
  • @dependabot show <dependency name> ignore conditions will show all of the ignore conditions of the specified dependency
  • @dependabot ignore this major version will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this minor version will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
  • @dependabot ignore this dependency will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)

Bumps [pyan3](https://github.com/Technologicat/pyan) from 2.4.0 to 2.6.1.
- [Release notes](https://github.com/Technologicat/pyan/releases)
- [Changelog](https://github.com/Technologicat/pyan/blob/master/CHANGELOG.md)
- [Commits](Technologicat/pyan@v2.4.0...v2.6.1)

---
updated-dependencies:
- dependency-name: pyan3
  dependency-version: 2.6.1
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
@dependabot @github

dependabot Bot commented on behalf of github Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Labels

The following labels could not be found: security. Please create it before Dependabot can add it to a pull request.

Please fix the above issues or remove invalid values from dependabot.yml.

@dependabot dependabot Bot added the python Python-specific runtime or environment optimizations label Jul 17, 2026
@dependabot
dependabot Bot requested a review from squid-protocol as a code owner July 17, 2026 10:24
@dependabot dependabot Bot added the python Python-specific runtime or environment optimizations label Jul 17, 2026
@github-actions

Copy link
Copy Markdown
Contributor

🐦‍⬛ Muninn Security Scan

✅ No security issues found.

🐦‍⬛ Powered by Muninn · Skald Lab

@squid-protocol
squid-protocol merged commit ea2e34d into main Jul 17, 2026
24 checks passed
@squid-protocol
squid-protocol deleted the dependabot/pip/pyan3-2.6.1 branch July 17, 2026 12:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

python Python-specific runtime or environment optimizations

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant