I’ve a project structured as follows:
.
├── hello
│ ├── __init__.py
│ └── animal.py
├── tests
│ ├── __init__.py
│ └── test_animal.py
├── README
└── pyproject.toml
This is just a personal Python library, and doesn’t need to be published or distributed. The usage consists of running pytest and mypy from the root directory.
Among other things, the pyproject.toml
contains the following sections:
[project.optional-dependencies]
test = [
"pytest",
]
lint = [
"ruff",
"mypy",
]
[tool.mypy]
exclude = [
'venv',
]
ignore_errors = false
warn_return_any = true
disallow_untyped_defs = true
I install the dependencies locally as follows:
% $(brew --prefix python)/bin/python3 -m venv ./venv
% ./venv/bin/python -m pip install --upgrade pip '.[test]' '.[lint]'
But my GitHub CI fails with the following error:
hello/__init__.py: error: Duplicate module named "hello" (also at "./build/lib/hello/__init__.py")
hello/__init__.py: note: See https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules for more info
hello/__init__.py: note: Common resolutions include: a) using `--exclude` to avoid checking one of them, b) adding `__init__.py` somewhere, c) using `--explicit-package-bases` or adjusting MYPYPATH
Found 1 error in 1 file (errors prevented further checking)
Error: Process completed with exit code 2.
As suggested, running mypy with --explicit-package-bases
fixes this problem, but so does addition of the following section in pyproject.toml
.
[tool.setuptools]
py-modules = []
I’ve reviewed the mypy, and setuptools documentations, but am not sure which of the two is better suited for my purpose, or why are they even necessary. As mentioned earlier, I’m not trying to publish or distribute this as a Python package.
Which one of the two configurations the recommended way to go, and why?
I found a pip ticket for this exact problem where pytest
was confused by the presence of a build
directory. One of the suggestions in the ticket was to ignore the build
directory. Apparently, in-place builds were introduced in pip 20.1, and is now the default.
The following configuration in pyproject.toml
solves the problem. However, it's a surprise that mypy does't exclude the directory automatically. I've created a ticket on their GitHub.
[tool.mypy]
exclude = [
"venv",
"build",
]