Skip to content

Commit 590db96

Browse files
authored
Update templates for new projects (#624)
* Update templates for new projects * add coverage * final Ruff update * fix * back to pytest-cov for subprocesses and xdist
1 parent eddb974 commit 590db96

15 files changed

+571
-71
lines changed

docs/config/project-templates.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The list of licenses should be composed of [SPDX identifiers](https://spdx.org/l
3232

3333
### Tests
3434

35-
This adds a `tests` directory with [pytest](https://github.com/pytest-dev/pytest) functionality.
35+
This adds a `tests` directory with environments for testing and linting.
3636

3737
=== ":octicons-file-code-16: config.toml"
3838

docs/environment.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -59,16 +59,16 @@ hatch run python -c "import sys;print(sys.executable)"
5959

6060
You can also run any [scripts](config/environment/overview.md#scripts) that have been defined.
6161

62-
You'll notice that in the `pyproject.toml` file there are already scripts defined in the `default` environment. Try running the `cov` command, which invokes [pytest](https://github.com/pytest-dev/pytest) with some flags for tracking [coverage](https://github.com/nedbat/coveragepy):
62+
You'll notice that in the `pyproject.toml` file there are already scripts defined in the `default` environment. Try running the `test` command, which invokes [pytest](https://github.com/pytest-dev/pytest) with some default arguments:
6363

6464
```
65-
hatch run cov
65+
hatch run test
6666
```
6767

68-
All additional arguments are passed through to scripts, so for example if you wanted to see the version of `pytest` and which plugins are installed you could do:
68+
All additional arguments are passed through to that script, so for example if you wanted to see the version of `pytest` and which plugins are installed you could do:
6969

7070
```
71-
hatch run cov -VV
71+
hatch run test -VV
7272
```
7373

7474
## Dependencies

docs/intro.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,10 @@ This would create the following structure in your current working directory:
1818

1919
```
2020
hatch-demo
21-
├── hatch_demo
22-
│ ├── __about__.py
23-
│ └── __init__.py
21+
├── src
22+
│ └── hatch_demo
23+
│ ├── __about__.py
24+
│ └── __init__.py
2425
├── tests
2526
│ └── __init__.py
2627
├── LICENSE.txt

docs/version.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ The `regex` source requires an option `path` that represents a relative path to
1212

1313
```toml
1414
[tool.hatch.version]
15-
path = "hatch_demo/__about__.py"
15+
path = "src/hatch_demo/__about__.py"
1616
```
1717

1818
=== ":octicons-file-code-16: hatch.toml"
1919

2020
```toml
2121
[version]
22-
path = "hatch_demo/__about__.py"
22+
path = "src/hatch_demo/__about__.py"
2323
```
2424

2525
The default pattern looks for a variable named `__version__` or `VERSION` that is set to a string containing the version, optionally prefixed with the lowercase letter `v`.

pyproject.toml

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,6 @@ exclude = [
7777
]
7878

7979
[tool.black]
80-
include = '\.pyi?$'
8180
line-length = 120
8281
skip-string-normalization = true
8382
target-version = ["py37"]
@@ -104,12 +103,17 @@ select = [
104103
"YTT",
105104
]
106105
ignore = [
106+
# Allow non-abstract empty methods in abstract base classes
107107
"B027",
108-
"FBT003",
108+
# Ignore McCabe complexity
109109
"C901",
110-
"S105",
110+
# Allow boolean positional values in function calls, like `dict.get(... True)`
111+
"FBT003",
112+
# Ignore checks for possible passwords
113+
"S105", "S106", "S107",
111114
]
112115
unfixable = [
116+
# Don't touch unused imports
113117
"F401",
114118
]
115119

@@ -128,7 +132,6 @@ ban-relative-imports = "all"
128132
"backend/tests/downstream/integrate.py" = ["T201"]
129133
"scripts/*" = ["T201"]
130134
# Tests can use relative imports and assertions
131-
"tests/*" = ["I252", "S101"]
132135
"tests/**/*" = ["I252", "S101"]
133136

134137
[tool.mypy]
@@ -175,8 +178,8 @@ omit = [
175178
]
176179

177180
[tool.coverage.paths]
178-
hatch = ["src", "*/hatch/src"]
179-
hatchling = ["backend/src", "*/hatch/backend/src"]
181+
hatch = ["src/hatch", "*/hatch/src/hatch"]
182+
hatchling = ["backend/src/hatchling", "*/hatch/backend/src/hatchling"]
180183
tests = ["tests", "*/hatch/tests"]
181184

182185
[tool.coverage.report]

src/hatch/template/files_default.py

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ def __init__(self, template_config: dict, plugin_config: dict):
99

1010
class MetadataFile(File):
1111
def __init__(self, template_config: dict, plugin_config: dict):
12-
super().__init__(Path(template_config['package_name'], '__about__.py'), "__version__ = '0.0.1'\n")
12+
super().__init__(Path(template_config['package_name'], '__about__.py'), '__version__ = "0.0.1"\n')
1313

1414

1515
class Readme(File):
@@ -68,6 +68,7 @@ class PyProject(File):
6868
6969
[project]
7070
name = "{project_name_normalized}"
71+
dynamic = ["version"]
7172
description = {description!r}
7273
readme = "{readme_file_path}"
7374
requires-python = ">=3.7"
@@ -88,7 +89,6 @@ class PyProject(File):
8889
"Programming Language :: Python :: Implementation :: PyPy",
8990
]
9091
dependencies = {dependency_data}
91-
dynamic = ["version"]
9292
9393
[project.urls]{project_url_data}{cli_scripts}
9494
@@ -140,19 +140,81 @@ def __init__(self, template_config: dict, plugin_config: dict):
140140
"pytest-cov",
141141
]
142142
[tool.hatch.envs.default.scripts]
143-
cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov={package_location}{template_config['package_name']} --cov=tests {{args}}"
144-
no-cov = "cov --no-cov {{args}}"
143+
test = "pytest --no-cov {{args:tests}}"
144+
test-cov = "pytest --cov --cov-report=term-missing --cov-config=pyproject.toml {{args:tests}}"
145145
146-
[[tool.hatch.envs.test.matrix]]
146+
[[tool.hatch.envs.all.matrix]]
147147
python = ["3.7", "3.8", "3.9", "3.10", "3.11"]
148148
149+
[tool.hatch.envs.lint]
150+
detached = true
151+
dependencies = [
152+
"black",
153+
"mypy",
154+
"ruff",
155+
]
156+
[tool.hatch.envs.lint.scripts]
157+
typing = "mypy --install-types --non-interactive {{args:{package_location}{template_config['package_name']} tests}}"
158+
style = [
159+
"ruff {{args:.}}",
160+
"black --check --diff {{args:.}}",
161+
]
162+
fmt = [
163+
"black {{args:.}}",
164+
"ruff --fix {{args:.}}",
165+
"style",
166+
]
167+
all = [
168+
"style",
169+
"typing",
170+
]
171+
172+
[tool.black]
173+
target-version = ["py37"]
174+
line-length = 120
175+
skip-string-normalization = true
176+
177+
[tool.ruff]
178+
target-version = "py37"
179+
line-length = 120
180+
select = ["A", "B", "C", "E", "F", "FBT", "I", "M", "N", "Q", "RUF", "S", "T", "U", "W", "YTT"]
181+
ignore = [
182+
# Allow non-abstract empty methods in abstract base classes
183+
"B027",
184+
# Ignore McCabe complexity
185+
"C901",
186+
# Allow boolean positional values in function calls, like `dict.get(... True)`
187+
"FBT003",
188+
# Ignore checks for possible passwords
189+
"S105", "S106", "S107",
190+
]
191+
unfixable = [
192+
# Don't touch unused imports
193+
"F401",
194+
]
195+
196+
[tool.ruff.isort]
197+
known-first-party = ["{template_config['package_name']}"]
198+
199+
[tool.ruff.flake8-tidy-imports]
200+
ban-relative-imports = "all"
201+
202+
[tool.ruff.per-file-ignores]
203+
# Tests can use relative imports and assertions
204+
"tests/**/*" = ["I252", "S101"]
205+
149206
[tool.coverage.run]
207+
source_pkgs = ["{template_config['package_name']}", "tests"]
150208
branch = true
151209
parallel = true
152210
omit = [
153211
"{package_location}{template_config['package_name']}/__about__.py",
154212
]
155213
214+
[tool.coverage.paths]
215+
{template_config['package_name']} = ["{package_location}{template_config['package_name']}", "*/{template_config['project_name_normalized']}/{package_location}{template_config['package_name']}"]
216+
tests = ["tests", "*/{template_config['project_name_normalized']}/tests"]
217+
156218
[tool.coverage.report]
157219
exclude_lines = [
158220
"no cov",

src/hatch/template/files_feature_cli.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ class PackageEntryPoint(File):
66
TEMPLATE = """\
77
import sys
88
9-
if __name__ == '__main__':
10-
from .cli import {package_name}
9+
if __name__ == "__main__":
10+
from {package_name}.cli import {package_name}
1111
1212
sys.exit({package_name}())
1313
"""
@@ -20,14 +20,14 @@ class CommandLinePackage(File):
2020
TEMPLATE = """\
2121
import click
2222
23-
from ..__about__ import __version__
23+
from {package_name}.__about__ import __version__
2424
2525
26-
@click.group(context_settings={{'help_option_names': ['-h', '--help']}}, invoke_without_command=True)
27-
@click.version_option(version=__version__, prog_name={project_name!r})
26+
@click.group(context_settings={{"help_option_names": ["-h", "--help"]}}, invoke_without_command=True)
27+
@click.version_option(version=__version__, prog_name="{project_name}")
2828
@click.pass_context
2929
def {package_name}(ctx: click.Context):
30-
click.echo('Hello world!')
30+
click.echo("Hello world!")
3131
"""
3232

3333
def __init__(self, template_config: dict, plugin_config: dict):

tests/helpers/templates/new/basic.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ def get_files(**kwargs):
2626
# SPDX-FileCopyrightText: {kwargs['year']}-present {kwargs['author']} <{kwargs['email']}>
2727
#
2828
# SPDX-License-Identifier: MIT
29-
__version__ = '0.0.1'
29+
__version__ = "0.0.1"
3030
""",
3131
),
3232
File(
@@ -64,6 +64,7 @@ def get_files(**kwargs):
6464
6565
[project]
6666
name = "{kwargs['project_name_normalized']}"
67+
dynamic = ["version"]
6768
description = ''
6869
readme = "README.md"
6970
requires-python = ">=3.7"
@@ -84,7 +85,6 @@ def get_files(**kwargs):
8485
"Programming Language :: Python :: Implementation :: PyPy",
8586
]
8687
dependencies = []
87-
dynamic = ["version"]
8888
8989
[project.urls]
9090
Documentation = "https://github.com/unknown/{kwargs['project_name_normalized']}#readme"

tests/helpers/templates/new/default.py

Lines changed: 67 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def get_files(**kwargs):
2828
# SPDX-FileCopyrightText: {kwargs['year']}-present {kwargs['author']} <{kwargs['email']}>
2929
#
3030
# SPDX-License-Identifier: MIT
31-
__version__ = '0.0.1'
31+
__version__ = "0.0.1"
3232
""",
3333
),
3434
File(
@@ -74,6 +74,7 @@ def get_files(**kwargs):
7474
7575
[project]
7676
name = "{kwargs['project_name_normalized']}"
77+
dynamic = ["version"]
7778
description = '{description}'
7879
readme = "README.md"
7980
requires-python = ">=3.7"
@@ -94,7 +95,6 @@ def get_files(**kwargs):
9495
"Programming Language :: Python :: Implementation :: PyPy",
9596
]
9697
dependencies = []
97-
dynamic = ["version"]
9898
9999
[project.urls]
100100
Documentation = "https://github.com/unknown/{kwargs['project_name_normalized']}#readme"
@@ -110,19 +110,81 @@ def get_files(**kwargs):
110110
"pytest-cov",
111111
]
112112
[tool.hatch.envs.default.scripts]
113-
cov = "pytest --cov-report=term-missing --cov-config=pyproject.toml --cov=src/{kwargs['package_name']} --cov=tests {{args}}"
114-
no-cov = "cov --no-cov {{args}}"
113+
test = "pytest --no-cov {{args:tests}}"
114+
test-cov = "pytest --cov --cov-report=term-missing --cov-config=pyproject.toml {{args:tests}}"
115115
116-
[[tool.hatch.envs.test.matrix]]
116+
[[tool.hatch.envs.all.matrix]]
117117
python = ["3.7", "3.8", "3.9", "3.10", "3.11"]
118118
119+
[tool.hatch.envs.lint]
120+
detached = true
121+
dependencies = [
122+
"black",
123+
"mypy",
124+
"ruff",
125+
]
126+
[tool.hatch.envs.lint.scripts]
127+
typing = "mypy --install-types --non-interactive {{args:src/{kwargs['package_name']} tests}}"
128+
style = [
129+
"ruff {{args:.}}",
130+
"black --check --diff {{args:.}}",
131+
]
132+
fmt = [
133+
"black {{args:.}}",
134+
"ruff --fix {{args:.}}",
135+
"style",
136+
]
137+
all = [
138+
"style",
139+
"typing",
140+
]
141+
142+
[tool.black]
143+
target-version = ["py37"]
144+
line-length = 120
145+
skip-string-normalization = true
146+
147+
[tool.ruff]
148+
target-version = "py37"
149+
line-length = 120
150+
select = ["A", "B", "C", "E", "F", "FBT", "I", "M", "N", "Q", "RUF", "S", "T", "U", "W", "YTT"]
151+
ignore = [
152+
# Allow non-abstract empty methods in abstract base classes
153+
"B027",
154+
# Ignore McCabe complexity
155+
"C901",
156+
# Allow boolean positional values in function calls, like `dict.get(... True)`
157+
"FBT003",
158+
# Ignore checks for possible passwords
159+
"S105", "S106", "S107",
160+
]
161+
unfixable = [
162+
# Don't touch unused imports
163+
"F401",
164+
]
165+
166+
[tool.ruff.isort]
167+
known-first-party = ["{kwargs['package_name']}"]
168+
169+
[tool.ruff.flake8-tidy-imports]
170+
ban-relative-imports = "all"
171+
172+
[tool.ruff.per-file-ignores]
173+
# Tests can use relative imports and assertions
174+
"tests/**/*" = ["I252", "S101"]
175+
119176
[tool.coverage.run]
177+
source_pkgs = ["{kwargs['package_name']}", "tests"]
120178
branch = true
121179
parallel = true
122180
omit = [
123181
"src/{kwargs['package_name']}/__about__.py",
124182
]
125183
184+
[tool.coverage.paths]
185+
{kwargs['package_name']} = ["src/{kwargs['package_name']}", "*/{kwargs['project_name_normalized']}/src/{kwargs['package_name']}"]
186+
tests = ["tests", "*/{kwargs['project_name_normalized']}/tests"]
187+
126188
[tool.coverage.report]
127189
exclude_lines = [
128190
"no cov",

0 commit comments

Comments
 (0)