Skip to content

add pyrefly type checking for new type errors - #2591

Open
pavelzw wants to merge 9 commits into
conda-forge:mainfrom
pavelzw:pyrefly
Open

add pyrefly type checking for new type errors#2591
pavelzw wants to merge 9 commits into
conda-forge:mainfrom
pavelzw:pyrefly

Conversation

@pavelzw

@pavelzw pavelzw commented Jun 14, 2026

Copy link
Copy Markdown
Member

as discussed in #2589

Closes #2602

Checklist

  • Added a news entry with any new deprecations added to the Deprecated section.
  • Regenerated schema JSON if schema altered (python -m conda_smithy.schema)
  • Regenerated linter documentation if any rules were added, removed or modified (python -m conda_smithy.linter.messages)

@pavelzw pavelzw changed the title add pyrefly type checking add pyrefly type checking for new type errors Jun 14, 2026
Comment thread .github/workflows/tests.yml Outdated
environment-file: environment.yml
micromamba-version: 1.5.12-0
cache-environment: true
cache-environment: false

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

cache-environment: true will give you a false sense of security since you don't use a lockfile.

Comment thread environment.yml
- setuptools>=80
- setuptools_scm>=8.1
- pre-commit
- pyrefly

@pavelzw pavelzw Jun 14, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this will lead to breakages with new pyrefly (or other dependencies') versions being released. my preferred workflow is having a lockfile to ensure CI is reproducibly green and then adding a regular lockfile updating job for pixi.lock as described in https://pixi.prefix.dev/latest/integration/ci/updates_github_actions/ and fix eventual failures here directly.

i strongly believe that this is a more seamless workflow and adding semver-style pins to everything and just running pixi upgrade which bumps those pins would make life simpler here.

happy to do introduce pixi here as well if this is wished but i don't want to impose my beliefs on other people (in this repository at least)

(i currently use pixi anyway on this repo with pixi.* and .pixi in .gitignore because i don't have conda/mamba installed on my system; having first party support for pixi in this repo would be nice anyway for people like me)

a pixi-based workflow would also make things like #2589 easier

Comment thread environment.yml
- setuptools>=80
- setuptools_scm>=8.1
- pre-commit
- pyrefly

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

other alternatives might be ty or mypy. i don't have strong opinions on this (apart from me wanting to not use mypy/pyright because they are slow) and don't know whether the python ecosystem will converge on ty or pyrefly or zuban. just using pyrefly because i've tried it out before and @ytausch likes it

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Some thoughts about mypy without having done any deep looking at the tradeoffs on this particular repo:

  • correctness
    • they all have false negatives/positives
  • performance
    • mypy recently added multi-core support, and is moving key pieces into rust
      • we (speaking as a member of @conda-forge/mypy) ship the dmypy extra by default (e.g. psutil)
  • integration
    • the editor plugins are fine
    • pyproject.toml is a fine place to write [tool] config, this repo hardly needs more /.{whatever} files
  • governance
    • mypy is an official (or at least blessed) python subproject vs a Big Corp project

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

until mypy has support for a proper lsp and is on a similar level in terms of performance as ty/pyrefly, i personally will not care about mypy

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

language server

👋 @conda-forge/mypy-ls

performance

🤷

$> time mypy -p conda_smithy
real	0m0.823s
user	0m2.251s
sys	0m0.383s
$> time pyrefly conda_smithy
real	0m0.684s
user	0m1.207s
sys	0m0.148s
$> time ty check conda_smithy
real	0m0.404s
user	0m1.330s
sys	0m0.149s

@pavelzw pavelzw Jul 16, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

https://github.com/python-lsp/pylsp-mypy does not look very "official (or at least blessed)" to me tbh; something directly part of mypy would be preferred by me

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

(@conda-forge/zuban is apparently broken)

Comment thread .pyrefly-baseline.json

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

this would allow us introducing pyrefly now without needing to fix 200 previous errors. would be nice to get rid of this file slowly through follow-ups

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

summary of remaining errors by codex:

• There are 220 current Pyrefly type errors in the project without the baseline.

  With .pyrefly-baseline.json, CI reports 0 errors, because those 220 existing diagnostics are baselined. The current breakdown is led by:

  - missing-attribute: 69
  - bad-argument-type: 27
  - unsupported-operation: 19
  - bad-override: 18
  - bad-assignment: 18
  - no-matching-overload: 14

  Command used:

  pixi run pyrefly check --python-interpreter-path $(pixi run which python) --output-format min-text --summary=none --progress-bar no --count-errors=0

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

this would allow us introducing pyrefly now without needing to fix 200 previous errors.

Could we not do a couple small precursor PRs that tackle different classes of errors before we switch on pyrefly? I'm not opposed to start with an exclude list, but if we can reduce this a bit beforehand, all the better.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

also fine with me, i can see what my agent can do

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

discussed a bit with my agent and we got the following plan:

🤖 yap
• Best grouping is by root cause/subsystem, not by Pyrefly error code. A single root cause often produces several codes, and fixing by code tends to create noisy cast-heavy PRs.

  I’d split it like this:

  PR 1: Obvious Runtime/Typing Fixes
  Low-risk fixes that are either real bugs or tiny annotation mismatches.

  Include:

  - bootstrap-obvious-ci-and-miniconda.py: urllib.urlretrieve should be urllib.request.urlretrieve.
  - simplejson.decoder.JSONDecodeError import/use.
  - datetime(..., tzinfo=...) issue in deprecations.py.
  - validate_schema.py optional schema_file typing.
  - contextmanager generator return in tests.
  - Simple uninitialized locals like old_val, runreqs_spacing, gh.

  Goal: knock out easy errors without touching architecture.

  PR 2: Linter Message Class Contracts
  This is self-contained and has lots of override errors.

  Include:

  - conda_smithy/linter/messages/base.py
  - conda_smithy/linter/messages/recipe.py
  - conda_smithy/linter/messages/conda_forge.py
  - related tests/registry typing

  Fix pattern:

  - Make base methods/properties have signatures that subclasses can legally override.
  - Use ClassVar where class-level metadata is intended.
  - Avoid mutable class attributes unless typed as ClassVar.
  - Make render/documentation hooks return one consistent type.

  This should clean up most bad-override, some bad-return, and not-callable.

  PR 3: Pydantic Schema Typing
  Keep conda_smithy/schema.py isolated. It has a distinct failure mode.

  Include:

  - model_config should likely be typed as ClassVar[ConfigDict].
  - Dynamic create_model(...) calls need better field typing, probably local helper wrappers/casts.
  - Functions returning generated models should return type[BaseModel], not BaseModel, if they return classes.
  - Literal field defaults need narrowing or explicit casts.

  Do not mix this with linter recipe fixes; it will be big enough on its own.

  PR 4: Recipe YAML Shape Narrowing
  This is probably the highest-value PR, but it needs care.

  Include:

  - conda_smithy/lint_recipe.py
  - conda_smithy/linter/lints.py
  - conda_smithy/linter/hints.py
  - conda_smithy/linter/utils.py
  - tests/test_lint_recipe.py

  Fix pattern:

  - Add small helper functions for dynamic recipe data:
      - as_mapping(value) -> Mapping[str, Any] | None
      - as_mutable_mapping(value) -> dict[str, Any]
      - as_list_of_mappings(value) -> list[dict[str, Any]]
      - as_string_list(value) -> list[str]
  - Narrow before calling .get, .items, or linter helper functions.
  - Prefer normalizing once near parse boundaries over sprinkling cast(...) everywhere.

  This should eliminate many missing-attribute, bad-argument-type, and test fixture errors.

  PR 5: Azure/GitHub Client Response Typing
  This is mostly third-party client typing friction.

  Include:

  - conda_smithy/azure_ci_utils.py
  - conda_smithy/anaconda_token_rotation.py
  - conda_smithy/feedstock_tokens.py
  - possibly conda_smithy/feedstock_io.py

  Fix pattern:

  - Add local typed wrappers around client calls.
  - Use typing.cast(...) at API boundaries only.
  - Add explicit None checks before indexing/attribute access.
  - Avoid propagating object | Unknown | None deeper into the code.

  This should clean up most Azure token/build-definition errors.

  PR 6: PyGithub / External Library Stub Mismatches
  Keep this separate because some fixes may be casts or ignores rather than code changes.

  Include:

  - conda_smithy/github.py
  - conda_smithy/cirun_utils.py
  - conda_smithy/feedstocks.py
  - tests/test_feedstock_io.py

  Fix pattern:

  - If runtime behavior is correct but stubs are incomplete, use narrow cast(...) near the call site.
  - If Pyrefly exposes a real bug, fix the call.
  - Avoid adding broad ignores for whole files.

  PR 7: Variant Algebra Type Cleanup
  This is algorithmic and should be reviewed separately.

  Include:

  - conda_smithy/variant_algebra.py
  - tests/test_variant_algebra.py

  Fix pattern:

  - Define aliases for variant values, e.g. VariantValue = str | float, VariantList = list[str] | list[float].
  - Narrow before indexing.
  - Split mixed numeric/string logic where Pyrefly cannot follow it.

  PR 8: Remaining Tests-Only Cleanup
  After production code is cleaner, handle test fixtures.

  Include:

  - tests/test_feedstock_tokens.py
  - leftover tests/test_lint_recipe.py
  - leftover registry/schema tests

  Fix pattern:

  - Annotate fixture return types.
  - Cast exception messages after checking they are not None.
  - Avoid intentionally heterogeneous test literals being inferred too broadly.

  Recommended order: 1, 2, 3, 4, 5, 6, 7, 8.

  The key rule: each PR should reduce one class of uncertainty. Avoid a “make Pyrefly green” mega-PR, and avoid adding broad suppressions early. Use casts mainly at external API boundaries and dynamic YAML boundaries; inside core logic, prefer real narrowing helpers and
  clearer types.

PR 1 is #2593

@pavelzw
pavelzw marked this pull request as ready for review June 14, 2026 09:50
@pavelzw
pavelzw requested a review from a team as a code owner June 14, 2026 09:50
Comment thread environment.yml
- pydantic>=2.11,<3
- pixi>=0.59.0
- jsonschema
- simplejson

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

@pavelzw pavelzw mentioned this pull request Jun 14, 2026
3 tasks
@h-vetinari

Copy link
Copy Markdown
Member

I'd prefer for us to first draw down the set of existing errors to something like <20.

@pavelzw

pavelzw commented Jun 17, 2026

Copy link
Copy Markdown
Member Author

I can start working on the next pr once #2593 is merged

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add pyrefly for type checking

4 participants