Skip to content

tooling: explore adding pyright in monitor mode to catch possibly-unbound variables #1075

Description

@lmeyerov

Problem

During #977 (cudf SIGSEGV fix), a real UnboundLocalError in hop.py was missed by both ruff and mypy:

# edge_map assigned only inside this branch:
if g_out._edges is not None and edge_hop_col is not None and ...:
    edge_map = ...

# then used outside it — NameError/UnboundLocalError at runtime:
if missing_mask.any() and edge_hop_col is not None and ...:
    ... safe_map_series(..., edge_map)  # edge_map possibly unbound!

The bug was masked by an upstream SIGSEGV (so it never surfaced in production), and only caught by writing a test that exercised the specific branch combination (`label_node_hops=True, label_edge_hops=None` with a non-empty `missing_mask`).

Why ruff/mypy missed it

  • ruff F821 only catches names with no assignment anywhere in scope — not conditionally-assigned names
  • mypy does not flag "possibly unbound" from conditional branches unless the variable is annotated before the branch (e.g. `edge_map: pd.Series` declared before the `if`)
  • Neither tool does full dataflow / reachability analysis for this pattern

What would catch it

pyright (default mode, not even strict) detects "possibly unbound" variables from conditional assignments and flags them at the use site. This is a well-known difference from mypy.

Proposal

Explore adding pyright in monitor / informational mode to CI as a sequence of stacked PRs:

  1. Observability
  • Run pyright on the `graphistry/` source (excluding tests, matching mypy.ini scope)
  • Enforce in CI any rules that already pass
  • Initially non-blocking (warnings only) for rest to assess the volume of pre-existing issues
  • Clear reporting step in CI for easy auditing
  1. Initial refactor
  • Create and implement on a metaissue for initial target of rules that the repo can enforce
  • There should be a small number of changes that go a long way
  • Promote these to blocking, and leave the rest as warning
  • For local dev flow, add pyright to the mypy steps as a default-on option
  1. Follow-on refactors
  • Track a metaissue prioritized rules that fail
  • Sequence of PRs that fix each one

This does not replace mypy — they catch different things. Pyright's dataflow analysis is complementary.

References

Activity

  1. JithinBathula commented on Apr 8, 2026

    @JithinBathula
    Contributor

    Hi, I would like to take this. Thanks

  2. lmeyerov commented on Apr 8, 2026

    @lmeyerov
    ContributorAuthor

    Great!

    Maybe try the non-ci aspects as easier to do locally ?

  3. added a commit that references this issue on Sep 18, 2026
    c343064
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions