Tests for pyrefly configuration files
Error on a non-existent search-path/site-package-path
$ mkdir $TMPDIR/test && echo "" > $TMPDIR/test/empty.py && \
> echo -e "project_includes = [\"$TMPDIR/test/empty.py\"]\nsite_package_path = [\"$TMPDIR/test/abcd\"]\nsearch_path = [\"$TMPDIR/test/efgh\"]" > $TMPDIR/test/pyrefly.toml && \
> $PYREFLY check -c $TMPDIR/test/pyrefly.toml --python-version 3.13.0
INFO Checking project configured at `*/pyrefly.toml` (glob)
WARN */pyrefly.toml: Invalid site-package-path: */abcd` does not exist (glob)
WARN */pyrefly.toml: Invalid search-path: */efgh` does not exist (glob)
INFO * errors* (glob)
[0]
Coverage commands also warn on a non-existent search-path/site-package-path
$ mkdir $TMPDIR/covwarn && echo "def f(): pass" > $TMPDIR/covwarn/f.py && \
> echo -e "project_includes = [\"$TMPDIR/covwarn/f.py\"]\nsite_package_path = [\"$TMPDIR/covwarn/abcd\"]\nsearch_path = [\"$TMPDIR/covwarn/efgh\"]" > $TMPDIR/covwarn/pyrefly.toml && \
> $PYREFLY coverage report -c $TMPDIR/covwarn/pyrefly.toml > /dev/null
INFO Checking project configured at `*/pyrefly.toml` (glob)
WARN */pyrefly.toml: Invalid site-package-path: */abcd` does not exist (glob)
WARN */pyrefly.toml: Invalid search-path: */efgh` does not exist (glob)
[0]
Dump config
$ touch $TMPDIR/foo.py && mkdir $TMPDIR/bar && touch $TMPDIR/bar/baz.py && touch $TMPDIR/bar/qux.py && mkdir $TMPDIR/spp && touch $TMPDIR/spp/mylib.py \
> && $PYREFLY dump-config --site-package-path $TMPDIR/spp/ $TMPDIR/foo.py $TMPDIR/bar/*.py
Default configuration
Using interpreter: * (glob)
Covered files:
*/bar/baz.py (glob)
*/bar/qux.py (glob)
Resolving imports from:
Fallback search path (guessed from importing file with heuristics): * (glob)
Site package path from user: * (glob)
Site package path queried from interpreter: * (glob)
Default configuration
Using interpreter: * (glob)
Covered files:
*/foo.py (glob)
Resolving imports from:
Fallback search path (guessed from importing file with heuristics): * (glob)
Site package path from user: * (glob)
Site package path queried from interpreter: * (glob)
[0]
Specify both files and config
$ echo "x: str = 0" > $TMPDIR/oops.py && echo "errors = { bad-assignment = false }" > $TMPDIR/pyrefly.toml && $PYREFLY check -c $TMPDIR/pyrefly.toml $TMPDIR/oops.py && rm $TMPDIR/pyrefly.toml
INFO 0 errors
[0]
Replaced imports remain dynamic when used as TypeVar bounds
$ mkdir $TMPDIR/replace_bound && \
> printf 'replace-imports-with-any = ["module.*"]\n' > $TMPDIR/replace_bound/pyrefly.toml && \
> printf 'class Foo: ...\n' > $TMPDIR/replace_bound/module.py && \
> printf 'from typing import TypeVar\nfrom module import Foo\n\nT = TypeVar("T", bound=Foo)\n\ndef f(arg: T) -> T:\n arg.method()\n return arg\n' > $TMPDIR/replace_bound/main.py && \
> $PYREFLY check -c $TMPDIR/replace_bound/pyrefly.toml --output-format=min-text $TMPDIR/replace_bound/main.py
INFO 0 errors
[0]
Error in implicit config (project mode)
$ mkdir $TMPDIR/bad_config && touch $TMPDIR/bad_config/empty.py && echo "oops oops" > $TMPDIR/bad_config/pyrefly.toml && cd $TMPDIR/bad_config && $PYREFLY check
WARN Config at `*/pyrefly.toml` failed to parse, checking with auto configuration (glob)
ERROR */pyrefly.toml: TOML parse error* (glob)
|
1 | oops oops
| ^
key with no value* (glob)
Fatal configuration error
[1]
Error in implicit config (file mode)
$ $PYREFLY check $TMPDIR/bad_config/empty.py
ERROR */pyrefly.toml: TOML parse error* (glob)
|
1 | oops oops
| ^
key with no value* (glob)
Fatal configuration error
[1]
Error in explicit config (project mode)
$ $PYREFLY check -c $TMPDIR/bad_config/pyrefly.toml
WARN Config at `*/pyrefly.toml` failed to parse, checking with auto configuration (glob)
ERROR */pyrefly.toml: TOML parse error* (glob)
|
1 | oops oops
| ^
key with no value* (glob)
Fatal configuration error
[1]
Error in explicit config (file mode)
$ $PYREFLY check -c $TMPDIR/bad_config/pyrefly.toml $TMPDIR/bad_config/empty.py
ERROR */pyrefly.toml: TOML parse error* (glob)
|
1 | oops oops
| ^
key with no value* (glob)
Fatal configuration error
[1]
We'll use the first marker file we find as a project root
$ mkdir -p $TMPDIR/config_finder/project && \
> touch $TMPDIR/config_finder/pyproject.toml && \
> touch $TMPDIR/config_finder/project/pyproject.toml && \
> touch $TMPDIR/config_finder/project/main.py && \
> $PYREFLY dump-config $TMPDIR/config_finder/project/main.py
Default configuration for project root marked by `*/config_finder/project/pyproject.toml` (glob)
* (glob+)
[0]
We'll prefer a Pyrefly config in a parent directory to a marker file
$ touch $TMPDIR/config_finder/pyrefly.toml && \
> $PYREFLY dump-config $TMPDIR/config_finder/project/main.py
Configuration at `*/config_finder/pyrefly.toml` (glob)
* (glob+)
[0]
We'll prefer a Pyproject with Pyrefly config in a parent directory to a marker file
$ rm $TMPDIR/config_finder/pyrefly.toml && \
> echo "[tool.pyrefly]" > $TMPDIR/config_finder/pyproject.toml && \
> $PYREFLY dump-config $TMPDIR/config_finder/project/main.py
Configuration at `*/config_finder/pyproject.toml` (glob)
* (glob+)
[0]
We'll use the first Pyrefly config we find
$ echo "[tool.pyrefly]" > $TMPDIR/config_finder/project/pyproject.toml && \
> $PYREFLY dump-config $TMPDIR/config_finder/project/main.py
Configuration at `*/config_finder/project/pyproject.toml` (glob)
* (glob+)
[0]
We'll prefer pyrefly.toml to pyproject.toml
$ touch $TMPDIR/config_finder/project/pyrefly.toml && \
> $PYREFLY dump-config $TMPDIR/config_finder/project/main.py
Configuration at `*/config_finder/project/pyrefly.toml` (glob)
* (glob+)
[0]
Skip hidden directories
$ mkdir $TMPDIR/contains_hidden && \
> mkdir $TMPDIR/contains_hidden/.hidden && \
> touch $TMPDIR/contains_hidden/ok.py && \
> echo "1 + 'oops'" > $TMPDIR/contains_hidden/.hidden/secret_error.py && \
> $PYREFLY check $TMPDIR/contains_hidden
[0]
We can still find hard-coded project-excludes when overridden
$ mkdir -p $TMPDIR/disable_excludes_heuristics/.src && \
> echo "x: str = 1" > $TMPDIR/disable_excludes_heuristics/.src/main.py && \
> touch $TMPDIR/disable_excludes_heuristics/pyrefly.toml && \
> $PYREFLY check -c $TMPDIR/disable_excludes_heuristics/pyrefly.toml --disable-project-excludes-heuristics --output-format=min-text
ERROR *main.py* ?bad-assignment? (glob)
[1]
We can still find hard-coded project-excludes when overridden in configs
$ echo "disable-project-excludes-heuristics = true" > $TMPDIR/disable_excludes_heuristics/pyrefly.toml && \
> PYREFLY_CONFIG="$TMPDIR/disable_excludes_heuristics/pyrefly.toml" $PYREFLY check $TMPDIR/disable_excludes_heuristics/.src/main.py --output-format=min-text
ERROR *main.py* ?bad-assignment? (glob)
[1]
Project inside hidden directory ancestor still reports errors
$ mkdir -p $TMPDIR/.hidden_workspace/project && \
> echo "x: str = 1" > $TMPDIR/.hidden_workspace/project/main.py && \
> touch $TMPDIR/.hidden_workspace/project/pyrefly.toml && \
> $PYREFLY check --output-format=min-text $TMPDIR/.hidden_workspace/project
ERROR *main.py* ?bad-assignment? (glob)
[1]
We can also find hidden pyrefly configs (.pyrefly.toml)
$ mkdir $TMPDIR/hidden_config && touch $TMPDIR/hidden_config/.pyrefly.toml && \
> touch $TMPDIR/hidden_config/main.py && \
> $PYREFLY dump-config $TMPDIR/hidden_config/main.py
Configuration at `*/hidden_config/.pyrefly.toml` (glob)
* (glob+)
[0]