facebook / facebook/pyrefly

PyTorch: Allow `matches` in `[[sub-config]]` to accept a list of paths/globs

Open
#4,462 4 comments 0 reactions 1 assignee Claimed by @cakeni View on GitHub
configuration pytorch
Dominant language
Rust
Stars
7k
Forks
516
PR merge metrics
No merged PRs in 30d

Description

## Summary

In `pyrefly.toml`, a `[[sub-config]]` block's `matches` key takes a single string. That string can be a glob, but there is no way to give one sub-config several distinct (unglobbed) file paths. The only workaround is to copy the entire `[sub-config.errors]` block once per file, which makes real-world configs enormously repetitive.

## Motivation / real example

The PyTorch pyrefly config (`pyrefly.toml`, based on `mypy.ini`) has **36 `[[sub-config]]` blocks**, and **31 of them have a byte-identical error body**:

```toml
[[sub-config]]
matches = "torch/_numpy/linalg.py"
[sub-config.errors]
implicit-import = false
implicit-any = true
bad-param-name-override = false
unannotated-return = true
unannotated-parameter = true
unannotated-attribute = true

[[sub-config]]
matches = "torch/_numpy/_reductions_impl.py"
[sub-config.errors]
implicit-import = false
implicit-any = true
bad-param-name-override = false
unannotated-return = true
unannotated-parameter = true
unannotated-attribute = true

# ... 29 more copies of the same six lines
```

Another 4 blocks share a different identical body:

```toml
[[sub-config]]
matches = "torch/_dynamo/**" # and torch/_dispatch/**, torch/_subclasses/**, torch/_functorch/**
[sub-config.errors]
implicit-import = false
implicit-any = true
```

The files being listed are genuinely unrelated paths (`torch/_numpy/*.py`, `torch/_export/**`, `torch/utils/_sympy/*.py`, `torch/optim/*.py`, `torch/_lazy/**`, ...), so a single glob cannot express the set — and a broad glob like `torch/_numpy/**` would be wrong, because it would pull in files that aren't ready for the stricter settings yet. So the duplication isn't a stylistic choice; it's forced.

Consequences:
- ~200 lines of copy-paste in one config file.
- Changing the shared policy (e.g. enabling `unannotated-attribute` in a later version, as the TODO in the dynamo section anticipates) means a 31-site edit, and any missed site silently diverges.
- Adding a newly-clean file to the strict set means pasting a 7-line stanza rather than adding one entry.

## Proposed fix

Let `matches` accept either a string or an array of strings, with array semantics being "this sub-config applies if any entry matches":

```toml
[[sub-config]]
matches = [
"torch/fx/**",
"torch/_lazy/**",
"torch/_inductor/fx_passes/serialized_patterns/**",
"torch/_numpy/linalg.py",
"torch/_numpy/_reductions_impl.py",
"torch/_numpy/fft.py",
# ...
"torch/optim/_functional.py",
]
[sub-config.errors]
implicit-import = false
implicit-any = true
bad-param-name-override = false
unannotated-return = true
unannotated-parameter = true
unannotated-attribute = true
```

That collapses the PyTorch config's 36 sub-configs down to roughly 3.

This mirrors what `project-includes` / `project-excludes` already do (both are lists of paths-or-globs), so the config language stays internally consistent and users don't have to remember which keys are scalar and which are lists.

## Notes / open questions

- Backwards compatible: a bare string should keep working, so existing configs are untouched. In serde terms this is an untagged `enum { One(String), Many(Vec) }` (or `#[serde(with = "string_or_seq")]`) on the `matches` field, plus updating the matcher to test any-of. This looks like a small, contained change — hence "pretty easy fix."
- **Precedence:** when a file is matched by more than one sub-config, the existing precedence rule should apply unchanged; a list entry should behave exactly as if it were its own single-`matches` sub-config with the same body. Worth stating explicitly in the docs, since lists make overlaps more likely.
- **Empty list:** `matches = []` should probably be a config error rather than a silently-inert sub-config.
- Docs for `sub-config` / `matches` need updating alongside the change, and a test covering a multi-entry `matches` plus the string form still parsing.

If a list is undesirable for some reason, the alternative that solves the same problem is named, reusable error profiles (define a settings bundle once, reference it from several sub-configs) — but the list form is the smaller change and matches existing config conventions.

PyTorch file https://github.com/pytorch/pytorch/blob/main/pyrefly.toml
cc @aorenste

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.