Description
Bug Report
At work, we have a standard project layout using namespace packages with dev/build/test dependencies declared in setup.py. It's a bit complex, but it worked well up until mypy 0.790. Since mypy 0.800, mypy is complaining: "Source file found twice under different module names".
This appears to be a rather obscure corner case requiring:
- implicit namespace packages
- dev dependencies declared in setup.py, rather than a requirements file
- use of
pip install -e .[dev]
to install those dependencies - running mypy on directories and files (not packages or modules)
Remove any of those conditions and mypy behaves as expected (ie. back to what we had under 0.790). But since it worked nicely under 0.790, it sure feels like a regression to me.
Here's a simplified version of the project layout, for a package fn.common
with one module and unit tests:
.
├── fn
│ └── common
│ ├── __init__.py
│ ├── py.typed
│ └── utils.py
├── setup.py
└── tests
├── __init__.py
└── test_utils.py
fn
is an implicit namespace package named after the company. We're Python 3 only, so we have no need for legacy namespace packages. Every project, whether library or application, puts all production code in fn/<something>
. Nice and clean and tidy and consistent.
The source code of the package isn't important. (There are type hints and no type errors.)
What matters is the contents of setup.py
, the way we initialize our virtualenv, and how we run mypy. Here's setup.py
:
import os
from setuptools import setup
install_requires = [] # type: ignore
dev_requires = ["mypy==0.790"]
packages = ["fn.common"]
package_data = {"fn.common": ["py.typed"]}
setup(
name="fnlib-common",
description="",
url="",
author="",
author_email="",
packages=packages,
package_data=package_data,
install_requires=install_requires,
extras_require={"dev": dev_requires},
)
This lets us create a virtualenv as follows:
$ /usr/local/bin/python3.8 -m venv venv
$ source venv/bin/activate
$ pip install -e '.[dev]'
Since I've pinned mypy to 0.790, it works fine:
$ mypy --ignore-missing-imports --check-untyped-defs fn tests *.py
Success: no issues found in 5 source files
If I upgrade to 0.812, it stops working:
$ pip install mypy==0.812
$ mypy --ignore-missing-imports --check-untyped-defs fn tests *.py
fn/common/__init__.py: error: Source file found twice under different module names: 'common' and 'fn.common'
Found 1 error in 1 file (errors prevented further checking)
The first release showing this behaviour was 0.800. I used git bisect
to track down the responsible commit: e4131a5.
To Reproduce
- get my source code:
$ wget https://www.gerg.ca/mypy/fnlib-common.tar.gz
$ tar -xzvf ~/fnlib-common.tar.gz
$ cd fnlib-common
- setup virtualenv:
$ python3 -m venv venv
$ source venv/bin/activate
$ pip install -e '.[dev]' # installs mypy 0.790
- run with mypy 0.790: no problem
$ mypy --ignore-missing-imports fn tests *.py
Success: no issues found in 5 source files
- upgrade to mypy >= 0.800 and see the problem
$ pip install mypy==0.800 # or later
$ mypy --ignore-missing-imports fn tests *.py
fn/common/__init__.py: error: Source file found twice under different module names: 'common' and 'fn.common'
Found 1 error in 1 file (errors prevented further checking)
Expected Behavior
Same output from mypy >= 0.800 as from mypy 0.790, i.e. no errors.
Actual Behavior
Errors from mypy >= 0.800.
Your Environment
host 1:
$ lsb_release -a
Distributor ID: Ubuntu
Description: Ubuntu 20.04.2 LTS
Release: 20.04
Codename: focal
$ /usr/local/bin/python3.8 --version
Python 3.8.6+
host 2:
$ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 10 (buster)
Release: 10
Codename: buster
$ /usr/bin/python3.7 --version
Python 3.7.3
Same results on host 1 and host 2.
No mypy config files -- command-line only.