Skip to content

Commit 006659d

Browse files
add mypy support
1 parent 52cd15a commit 006659d

File tree

7 files changed

+91
-29
lines changed

7 files changed

+91
-29
lines changed

copier.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,11 @@ use_precommit:
151151
default: "{% if template_mode != 'minimal' %}yes{% else %}no{% endif %}"
152152
help: "Do you want to pre-commit hooks to format your code on save?"
153153

154-
use_types:
154+
use_mypy:
155155
when: "{{ template_mode == 'custom' }}"
156156
type: bool
157157
default: "{% if template_mode != 'minimal' %}yes{% else %}no{% endif %}"
158-
help: "Do you want to use typing annotations and type check your code?"
158+
help: "Do you want to use mypy to check type annotations?"
159159

160160
############### All things related to testing ###################
161161

includes/pyproject/deps-pep-621.toml.jinja

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ style = [
2727
"ruff",
2828
]
2929
{% endif %}
30-
{%- if use_types -%}
30+
{%- if use_mypy -%}
3131
types = [
3232
"mypy",
3333
]

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ ignore = [
3535
"S602",
3636
"S603",
3737
"S607",
38+
"FBT001", # boolean positional arguments are fine always but especially in tests
3839
]
3940

4041
[tool.ruff.lint.isort]

template/pyproject.toml.jinja

Lines changed: 14 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ classifiers = [
4545
{% endif -%}
4646
"Operating System :: OS Independent",
4747
"Programming Language :: Python :: 3 :: Only",
48-
{%- if use_types %}
48+
{%- if use_mypy %}
4949
"Typing :: Typed",
5050
{%- endif %}
5151
]
@@ -72,7 +72,7 @@ dev = [
7272
{%- if documentation!="" %}docs,{% endif -%}
7373
{%- if use_test %}tests,{% endif -%}
7474
{%- if use_lint %}style,{% endif -%}
75-
{%- if use_types %}types,{% endif -%}
75+
{%- if use_mypy %}types,{% endif -%}
7676
audit]",
7777
{%- endif %}
7878
]
@@ -179,7 +179,7 @@ lines-after-imports = 1
179179

180180
[tool.pydoclint]
181181
style = "numpy"
182-
{%- if use_types %}
182+
{%- if use_mypy %}
183183
arg-type-hints-in-signature = true
184184
{%- else %}
185185
arg-type-hints-in-signature = false
@@ -192,24 +192,16 @@ exclude = "_version.py"
192192
{%- endif %}
193193
{%- endif %}
194194

195-
{%- if use_types %}
196-
# TODO: Adjust mypy configuration.
197-
#[tool.mypy]
198-
#plugins = [
199-
# "pydantic.mypy",
200-
#]
201-
202-
# Stop mypy from complaining about missing types from imports.
203-
#[[tool.mypy.overrides]]
204-
#module = [
205-
# "pandas",
206-
#]
207-
#ignore_missing_imports = true
208-
209-
#[tool.pydantic-mypy]
210-
#init_forbid_extra = true
211-
#init_typed = true
212-
#warn_required_dynamic_aliases = true
195+
{%- if use_mypy %}
196+
[tool.mypy]
197+
packages = ["{{ package_name }}"]
198+
warn_redundant_casts = true
199+
warn_unused_ignores = true
200+
show_error_context = true
201+
show_column_numbers = true
202+
show_error_code_links = true
203+
pretty = true
204+
color_output = true
213205
{%- endif %}
214206

215207
{%- if use_hatch_envs %}
@@ -242,7 +234,7 @@ extra-dependencies = [
242234
[tool.hatch.envs.audit.scripts]
243235
check = ["pip-audit"]
244236

245-
{%- if use_types %}
237+
{%- if use_mypy %}
246238
[tool.hatch.envs.types]
247239
description = """Check the static types of the codebase."""
248240
dependencies = [

template/{% if use_git and dev_platform == 'GitHub' %}.github{% endif %}/workflows/test.yml.jinja

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ jobs:
6767
- name: Check dependencies
6868
run: hatch run audit:check
6969

70-
{%- if use_types %}
70+
{%- if use_mypy %}
7171
- name: Check types
7272
run: hatch run types:check
7373
{%- endif %}
@@ -82,4 +82,27 @@ jobs:
8282
run: bash <(curl -s https://codecov.io/bash)
8383
{%- endraw %}
8484
{%- endif %}
85+
{%- else %}
86+
87+
- name: Install package
88+
run: python -m pip install '.[dev]'
89+
90+
- name: Check dependencies
91+
run: python -m pip-audit
92+
93+
{%- if use_mypy %}
94+
95+
- name: Check types
96+
run: python -m mypy
97+
{%- endif %}
98+
99+
{%- if use_test %}
100+
101+
- name: Run tests
102+
run: python -m pytest --cov={{ package_name }} --cov-report=term-missing
103+
104+
- name: Report coverage
105+
shell: bash
106+
run: bash <(curl -s https://codecov.io/bash)
107+
{%- endif %}
85108
{%- endif %}

tests/conftest.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
"""Provide fixtures to the entire test suite."""
22

33
import shutil
4+
from collections.abc import Generator
45
from pathlib import Path
5-
from typing import TYPE_CHECKING, Generator
6+
from typing import TYPE_CHECKING
67

78
import pytest
89
from _pytest.monkeypatch import MonkeyPatch

tests/test_template_init.py

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,10 @@
2222
import os
2323
import subprocess
2424
import sys
25+
import venv
2526
from datetime import datetime, timezone
2627
from pathlib import Path
28+
from textwrap import dedent
2729
from typing import Callable
2830

2931
import pytest
@@ -196,7 +198,7 @@ def test_docs_build(documentation: str, generated: Callable[..., Path], use_hatc
196198
)
197199
run_command("sphinx-apidoc -o docs/api src/alien_clones", project)
198200
# prepend pythonpath so we don't have to actually install here...
199-
run_command(f"PYTHONPATH={str(project/'src')} sphinx-build -W -b html docs docs/_build", project)
201+
run_command(f"PYTHONPATH={project/'src'!s} sphinx-build -W -b html docs docs/_build", project)
200202

201203
run_command("pre-commit run --all-files -v check-readthedocs", project)
202204

@@ -229,7 +231,7 @@ def test_non_hatch_deps(
229231
project = generated(
230232
use_hatch_envs=False,
231233
use_lint=True,
232-
use_types=True,
234+
use_mypy=True,
233235
use_test=True,
234236
use_git=False,
235237
documentation=documentation,
@@ -254,3 +256,46 @@ def test_non_hatch_deps(
254256
if documentation != "no":
255257
assert "docs" in optional_deps
256258
assert any(dep.startswith(documentation) for dep in optional_deps["docs"])
259+
260+
@pytest.mark.parametrize("use_hatch_envs", [True, False])
261+
@pytest.mark.parametrize("valid", [True, False])
262+
def test_mypy(generated: Callable[..., Path], use_hatch_envs: bool, valid: bool, tmp_path: Path):
263+
"""Mypy type checking works out of the box."""
264+
if valid:
265+
module = dedent("""
266+
def f1(value: int, other: int = 2) -> int:
267+
return value * other
268+
269+
def f2(value: int) -> float:
270+
return f1(value, 5) / 2
271+
""")
272+
else:
273+
module = dedent("""
274+
def f1(value: int, other: int = 2) -> int:
275+
return value * other
276+
277+
def f2(value: str) -> str:
278+
return f1(value, 5) / 2
279+
""")
280+
281+
root = generated(use_hatch_envs=use_hatch_envs, use_mypy=True)
282+
pkg_path = root / "src" / "alien_clones"
283+
module_path = pkg_path / "typechecking.py"
284+
with module_path.open("w") as f:
285+
f.write(module)
286+
287+
if use_hatch_envs:
288+
command = "hatch run types:check"
289+
else:
290+
venv_path = tmp_path / ".venv"
291+
mypy_path = venv_path / "bin" / "mypy"
292+
python_path = venv_path / "bin" / "python"
293+
venv.EnvBuilder(with_pip=True).create(venv_path)
294+
run_command(f"{python_path!s} -m pip install -e '.[types]'", root)
295+
command = f"{mypy_path!s} {pkg_path!s}"
296+
297+
if valid:
298+
run_command(command, root)
299+
else:
300+
with pytest.raises(subprocess.CalledProcessError):
301+
run_command(command, root)

0 commit comments

Comments
 (0)