Description
There appears to be a cache invalidation issue with mypy
running over a Python 2 and 3 compatible subpackage.
The reproducible test script is below. However, a few things should be noted:
- While
.pyi
file is erroneously not specified inpackage_data
– it is critical for illustrating the issue. This is technically a bug in the packaging part when stumbling across this. It should also be noted that adding the.pyi
file to be installed does resolve the issue. However,mypy
acts in an unexpected way when it is not properly packaged. - Note that the
packages
line insetup.py
only installs the subpackage only. The reason being is that for Python 2, we don't wantsome_package/__init__.py
being installed which is provided by a separate Python package (e.g.,install_requires['some_package; python_version < "3.3"']
).
# In an activated virtual environment...
mkdir -p mypy_test_case
cd mypy_test_case
cat >setup.py <<EOF
from setuptools import setup
setup(
name="some_package.some_subpackage",
version="0.0.1",
package_dir={"": "src"},
packages=["some_package.some_subpackage"],
package_data={"some_package.some_subpackage": ["py.typed"]},
)
EOF
mkdir -p src/some_package/some_subpackage
touch src/some_package/__init__.py
touch src/some_package/some_subpackage/py.typed
cat >src/some_package/some_subpackage/__init__.py <<EOF
from ._some_submodule import find_the_answer
def print_the_answer() -> None:
print(find_the_answer())
EOF
cat >src/some_package/some_subpackage/_some_submodule.pyi <<EOF
def find_the_answer() -> int: ...
EOF
python -m pip install .
python -m pip install mypy
# Observe mypy passes.
python -m mypy -vv --strict src/some_package/some_subpackage
# Observe mypy fails.
python -m mypy -vv --strict -m some_package.some_subpackage
# Observe mypy passes.
python -m mypy -vv --strict -m some_package.some_subpackage
What is interesting is that the second invocation of mypy
fails with something like:
Parsing /Users/eric/.pyenv/versions/test-dev/lib/python3.8/site-packages/some_package/some_subpackage/__init__.py (some_package.some_subpackage)
/Users/eric/.pyenv/versions/test-dev/lib/python3.8/site-packages/some_package/some_subpackage/__init__.py:1: error: Cannot find implementation or library stub for module named 'some_package.some_subpackage._some_submodule'
/Users/eric/.pyenv/versions/test-dev/lib/python3.8/site-packages/some_package/some_subpackage/__init__.py:1: note: See https://mypy.readthedocs.io/en/latest/running_mypy.html#missing-imports
However, the third (last) invocation succeeds 🤷♂.
Quickly looking at the verbose output (-vv
) it appears that when the first invocation of mypy
is run, it caches the dependency for _some_submodule.pyi
. When the second invocation occurs, it complains because it is unable to find _some_submodule.pyi
or _some_submodule.py
— then deletes the cached metadata. Upon the third run of mypy
, it re-parses and succeeds, treating, I believe, the unknown import as Any
.
My expectation would be for the second and third invocation to either both fail or both succeed.