Tests for specifying options as command line arguments
We can manually override typing_extensions
$ mkdir $TMPDIR/typing_extensions_project && \
> echo "x: int = 42" > $TMPDIR/typing_extensions_project/typing_extensions.py && \
> echo "from typing_extensions import x; y: int = x" > $TMPDIR/typing_extensions_project/foo.py && \
> $PYREFLY check $TMPDIR/typing_extensions_project/foo.py --search-path $TMPDIR/typing_extensions_project
[0]
We don't accidentally override typing_extensions with an installed package
$ mkdir $TMPDIR/site_package_path && \
> echo "x: int = 42" > $TMPDIR/site_package_path/typing_extensions.py && \
> echo "from typing import TypedDict; from typing_extensions import NotRequired; class C(TypedDict): x: NotRequired[int]" > $TMPDIR/site_package_path/lib.py && \
> echo "from lib import C; C()" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --site-package-path $TMPDIR/site_package_path
[0]
Partial stub packages fall back to runtime modules
$ touch $TMPDIR/pyrefly.toml && \
> mkdir -p $TMPDIR/partial_site/lib $TMPDIR/partial_site/lib-stubs && \
> echo 'a = "runtime"' > $TMPDIR/partial_site/lib/__init__.py && \
> echo 'c = "runtime"' > $TMPDIR/partial_site/lib/b.py && \
> echo 'partial' > $TMPDIR/partial_site/lib-stubs/py.typed && \
> echo 'c: int' > $TMPDIR/partial_site/lib-stubs/b.pyi && \
> echo -e 'from typing import reveal_type\nfrom lib import a\nfrom lib.b import c\nreveal_type(a)\nreveal_type(c)' > $TMPDIR/partial.py && \
> $PYREFLY check $TMPDIR/partial.py --python-version 3.13.0 --site-package-path $TMPDIR/partial_site --output-format=min-text
INFO * revealed type: str * (glob)
INFO * revealed type: int * (glob)
[0]
Error on missing source
$ mkdir $TMPDIR/site_package_missing_source && \
> mkdir $TMPDIR/site_package_missing_source/pkg-stubs && \
> echo "class X: ..." > $TMPDIR/site_package_missing_source/pkg-stubs/__init__.py && \
> echo "from pkg import X" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --error=missing-source --site-package-path $TMPDIR/site_package_missing_source --output-format=min-text
ERROR * Found stubs for `pkg`, but no source* (glob)
[1]
We can disable missing-source on the command line
$ mkdir $TMPDIR/error_missing_source && \
> echo -e '[errors]\nmissing-source="error"' > $TMPDIR/error_missing_source/pyrefly.toml && \
> echo "from pkg import X" > $TMPDIR/error_missing_source/foo.py && \
> $PYREFLY check $TMPDIR/error_missing_source/foo.py --ignore=missing-source --site-package-path $TMPDIR/site_package_missing_source --output-format=min-text
[0]
We can enable an error that is default-off
$ echo -e '[errors]\nmissing-source=true' > $TMPDIR/error_missing_source/pyrefly.toml && \
> $PYREFLY check $TMPDIR/error_missing_source/foo.py --site-package-path $TMPDIR/site_package_missing_source --output-format=min-text
ERROR * [missing-source] (glob)
[1]
Regression test: we should still be able to find submodules when stubs are missing
$ touch $TMPDIR/pyrefly.toml && \
> mkdir $TMPDIR/site_package_missing_stubs && \
> mkdir $TMPDIR/site_package_missing_stubs/django && \
> touch $TMPDIR/site_package_missing_stubs/django/__init__.py && \
> mkdir $TMPDIR/site_package_missing_stubs/django/forms && \
> touch $TMPDIR/site_package_missing_stubs/django/forms/__init__.py && \
> echo "from django import forms; from typing import reveal_type; reveal_type(forms)" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --error untyped-import --ignore missing-module-attribute --site-package-path $TMPDIR/site_package_missing_stubs --output-format=min-text
ERROR * Cannot find type stubs for module `django` * (glob)
INFO * revealed type: Module[django.forms] * (glob)
[1]
The --preset flag sets the preset and suppresses the upsell
$ PRESET_DIR=$(mktemp -d -p /tmp preset.XXXXXX) && \
> echo "x = unknown_name" > $PRESET_DIR/foo.py && \
> $PYREFLY check $PRESET_DIR/foo.py --preset off; rm -rf $PRESET_DIR
INFO 0 errors
[0]
Error mappings in the config file override --preset
$ echo -e '[errors]\nimplicit-any = "ignore"' > $TMPDIR/pyrefly.toml && \
> echo "x = []" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --preset strict --output-format=min-text
[0]
Scalar fields in the config file override --preset
$ echo "check-unannotated-defs = true" > $TMPDIR/pyrefly.toml && \
> echo -e "def f():\n x = unknown_name" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --preset basic --output-format=min-text
ERROR * [unknown-name] (glob)
[1]
--preset in a directory with mypy.ini should not inherit migrated values
$ MYPY_DIR=$(mktemp -d -p /tmp mypy.XXXXXX) && \
> echo -e "[mypy]\ncheck_untyped_defs = False" > $MYPY_DIR/mypy.ini && \
> echo -e "def f():\n x: int = 'hello'" > $MYPY_DIR/foo.py && \
> $PYREFLY check $MYPY_DIR/foo.py --preset strict --output-format=min-text; rc=$?; rm -rf $MYPY_DIR; exit $rc
ERROR * [bad-assignment] (glob)
[1]
CLI error flags override --preset
$ touch $TMPDIR/pyrefly.toml && \
> echo "x: int = 'hello'" > $TMPDIR/foo.py && \
> $PYREFLY check $TMPDIR/foo.py --preset off --error bad-assignment --output-format=min-text
ERROR * [bad-assignment] (glob)
[1]