Skip to content

Commit 05d102a

Browse files
committed
Split mypy check for the source package and dev files
`mypy` tends to have issues with checking source files inside a `src/` directory. There are tricks[1] but it seems like the only way to do it is to run `mypy` on `.` using `MYPYPATH=src`, which will still check the whole `.` directory (include whole virtualenvs if there are any), which is not what we want. For now we've been using `-p` to check for packages instead of files, which seemed to have done the trick, but we need to pass directories that don't really have a package structure (like benchmarks or examples or tests) as packages, which is also not great. This commit tries a different approach, we check the source code as a package separately, and then check the development files (tests, examples, etc.), which are passed as simple paths. This also opens up the door to using more relaxed rules for these development files if needed in the future. To achieve this we also move the `packages` specification to the `pyproject.toml` file, so now `mypy` can be called without any arguments to check the source code package, making it easier to call it without relaying in `nox`. [1] https://mypy.readthedocs.io/en/stable/running_mypy.html#mapping-file-paths-to-modules Signed-off-by: Leandro Lucarella <[email protected]>
1 parent 4d2c29b commit 05d102a

File tree

5 files changed

+39
-6
lines changed

5 files changed

+39
-6
lines changed

cookiecutter/{{cookiecutter.github_repo_name}}/pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,7 @@ testpaths = ["pytests"]
170170
[tool.mypy]
171171
explicit_package_bases = true
172172
namespace_packages = true
173+
packages = ["{{cookiecutter.python_package}}"]
173174
strict = true
174175

175176
[[tool.mypy.overrides]]

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,7 @@ disable = [
152152
[tool.mypy]
153153
explicit_package_bases = true
154154
namespace_packages = true
155+
packages = ["frequenz.repo.config"]
155156
strict = true
156157

157158
[[tool.mypy.overrides]]

src/frequenz/repo/config/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,9 +182,13 @@
182182
[tool.mypy]
183183
explicit_package_bases = true
184184
namespace_packages = true
185+
packages = ["your_package_name"] # Use the actual package name here
185186
strict = true
186187
```
187188
189+
You can just call `mypy` to check the package of your sources or you can use `mypy
190+
tests` to check the tests, for example.
191+
188192
## `mkdocs` (generating documentation)
189193
190194
### API reference generation

src/frequenz/repo/config/nox/config.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,14 @@ def copy(self, /) -> Self:
114114
extra_paths=self.extra_paths.copy(),
115115
)
116116

117-
def path_args(self, session: _nox.Session, /) -> list[str]:
117+
def path_args(
118+
self,
119+
session: _nox.Session,
120+
/,
121+
*,
122+
include_sources: bool = True,
123+
include_extra: bool = True,
124+
) -> list[str]:
118125
"""Return the file paths to run the checks on.
119126
120127
If positional arguments are present in the nox session, those are used
@@ -123,16 +130,22 @@ def path_args(self, session: _nox.Session, /) -> list[str]:
123130
124131
Args:
125132
session: The nox session to use to look for command-line arguments.
133+
include_sources: Whether to include the source paths or not.
134+
include_extra: Whether to include the extra paths or not.
126135
127136
Returns:
128137
The file paths to run the checks on.
129138
"""
130139
if session.posargs:
131140
return session.posargs
132141

133-
return list(
134-
str(p) for p in _util.existing_paths(self.source_paths + self.extra_paths)
135-
)
142+
paths: list[str] = []
143+
if include_sources:
144+
paths.extend(self.source_paths)
145+
if include_extra:
146+
paths.extend(self.extra_paths)
147+
148+
return list(str(p) for p in _util.existing_paths(paths))
136149

137150
def package_args(self, session: _nox.Session, /) -> list[str]:
138151
"""Return the package names to run the checks on.

src/frequenz/repo/config/nox/session.py

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -62,8 +62,22 @@ def mypy(session: nox.Session, install_deps: bool = True) -> None:
6262
session.install("-e", ".[dev-mypy]")
6363

6464
conf = _config.get()
65-
pkg_args = _util.flatten(("-p", p) for p in conf.package_args(session))
66-
session.run("mypy", *conf.opts.mypy, *pkg_args)
65+
66+
# If we get CLI options, we run mypy on those, but still passing the
67+
# configured options (they can be overridden by the CLI options).
68+
if session.posargs:
69+
session.run("mypy", *conf.opts.mypy, *session.posargs)
70+
return
71+
72+
# We separate running the mypy checks into two runs, one is the default, as
73+
# configured in `pyproject.toml`, which should run against the sources.
74+
session.run("mypy", *conf.opts.mypy)
75+
76+
# The second run checks development files, like tests, benchmarks, etc.
77+
# This is an attempt to minimize mypy internal errors.
78+
session.run(
79+
"mypy", *conf.opts.mypy, *conf.path_args(session, include_sources=False)
80+
)
6781

6882

6983
@nox.session

0 commit comments

Comments
 (0)