Skip to content

Cache invalidation issue with missing installed .pyi file #8211

Closed
@ericvw

Description

@ericvw

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 in package_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 in setup.py only installs the subpackage only. The reason being is that for Python 2, we don't want some_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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions