Skip to content

Commit 4ea8aea

Browse files
authored
Merge pull request #9 from 56kyle/develop
develop
2 parents f34b8be + 2055afa commit 4ea8aea

25 files changed

+190
-67
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
/dist/
88
/docs/_build/
99
/src/*.egg-info/
10+
*.egg-info/
1011

1112
# Byte-code files
1213
*.pyc

.ruff.toml

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
2+
# Exclude a variety of commonly ignored directories.
3+
# Most importantly, don't lint the inner jinja affected files.
4+
exclude = [
5+
".bzr",
6+
".direnv",
7+
".eggs",
8+
".git",
9+
".git-rewrite",
10+
".hg",
11+
".ipynb_checkpoints",
12+
".mypy_cache",
13+
".nox",
14+
".pants.d",
15+
".pyenv",
16+
".pytest_cache",
17+
".pytype",
18+
".ruff_cache",
19+
".svn",
20+
".tox",
21+
".venv",
22+
".vscode",
23+
"__pypackages__",
24+
"_build",
25+
"buck-out",
26+
"build",
27+
"dist",
28+
"node_modules",
29+
"site-packages",
30+
"venv",
31+
"[{][{]cookiecutter.project_name[}][}]",
32+
]
33+
34+
# Same as Black.
35+
line-length = 120
36+
indent-width = 4
37+
38+
# Assume Python 3.9
39+
target-version = "py39"
40+
41+
[lint]
42+
# https://docs.astral.sh/ruff/rules
43+
select = [
44+
"A",
45+
"ARG",
46+
"B",
47+
"B9",
48+
"BLE",
49+
"C",
50+
"C4",
51+
"D",
52+
"DTZ",
53+
"E",
54+
"F",
55+
"I",
56+
"N",
57+
"PT",
58+
"PTH",
59+
"Q",
60+
"RET",
61+
"RUF",
62+
"S",
63+
"SIM",
64+
"SLF",
65+
"T10",
66+
"TC",
67+
"W"
68+
]
69+
ignore = ["E203", "E501"]
70+
71+
72+
# Allow fix for all enabled rules (when `--fix`) is provided.
73+
fixable = ["ALL"]
74+
unfixable = []
75+
76+
# Allow unused variables when underscore-prefixed.
77+
dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$"
78+
79+
[lint.flake8-quotes]
80+
inline-quotes = "double"
81+
82+
[lint.isort]
83+
force-single-line = true
84+
lines-after-imports = 2
85+
86+
[lint.mccabe]
87+
max-complexity = 10
88+
89+
[lint.per-file-ignores]
90+
"tests/*" = [
91+
"S101",
92+
"D100",
93+
"D101",
94+
"D102",
95+
"D103",
96+
"D104",
97+
"ARG001",
98+
"C408",
99+
"SLF001"
100+
]
101+
"exceptions.py" = ["D107"]
102+
"noxfile.py" = ["S101"]
103+
104+
[lint.pydocstyle]
105+
convention = "google"
106+
107+
[format]
108+
# Like Black, use double quotes for strings.
109+
quote-style = "double"
110+
111+
# Like Black, indent with spaces, rather than tabs.
112+
indent-style = "space"
113+
114+
# Like Black, respect magic trailing commas.
115+
skip-magic-trailing-comma = false
116+
117+
# Like Black, automatically detect the appropriate line ending.
118+
line-ending = "auto"
119+
120+
# Enable auto-formatting of code examples in docstrings. Markdown,
121+
# reStructuredText code/literal blocks and doctests are all supported.
122+
#
123+
# This is currently disabled by default, but it is planned for this
124+
# to be opt-out in the future.
125+
docstring-code-format = false
126+
127+
# Set the line length limit used when formatting code snippets in
128+
# docstrings.
129+
#
130+
# This only has an effect when the `docstring-code-format` setting is
131+
# enabled.
132+
docstring-code-line-length = "dynamic"

docs/conf.py

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from datetime import date
66

7+
78
# --- Project information -----------------------------------------------------
89

910
# General info about the TEMPLATE documentation itself
@@ -59,8 +60,19 @@
5960

6061
# MyST-Parser settings (allows using Markdown + Sphinx features)
6162
myst_enable_extensions = [
62-
"amsmath", "colon_fence", "deflist", "dollarmath", "html_admonition", "html_image", "replacements",
63-
"smartquotes", "strikethrough", "substitution", "tasklist", "attrs_inline", "attrs_block",
63+
"amsmath",
64+
"colon_fence",
65+
"deflist",
66+
"dollarmath",
67+
"html_admonition",
68+
"html_image",
69+
"replacements",
70+
"smartquotes",
71+
"strikethrough",
72+
"substitution",
73+
"tasklist",
74+
"attrs_inline",
75+
"attrs_block",
6476
]
6577

6678
# Intersphinx mapping: Link to documentation of standard libraries or tools mentioned
@@ -85,7 +97,6 @@
8597
"sidebar_hide_name": True, # Hide project name next to logo if logo contains it
8698
# "light_logo": "logo-light.png",
8799
# "dark_logo": "logo-dark.png",
88-
89100
# Footer icons
90101
"footer_icons": [
91102
{

noxfile.py

Lines changed: 13 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Noxfile for the cookiecutter-robust-python template."""
2-
from pathlib import Path
2+
33
import shutil
44
import tempfile
5+
from pathlib import Path
56

67
import nox
78
import platformdirs
@@ -41,11 +42,7 @@
4142
*("--demo-name", DEFAULT_DEMO_NAME),
4243
)
4344

44-
TEMPLATE_PYTHON_LOCATIONS: tuple[Path, ...] = (
45-
Path("noxfile.py"),
46-
Path("scripts/*"),
47-
Path("hooks/*")
48-
)
45+
TEMPLATE_PYTHON_LOCATIONS: tuple[Path, ...] = (Path("noxfile.py"), Path("scripts"), Path("hooks"))
4946

5047
TEMPLATE_CONFIG_AND_DOCS: tuple[Path, ...] = (
5148
Path("pyproject.toml"),
@@ -59,7 +56,7 @@
5956
Path("LICENSE"),
6057
Path("CODE_OF_CONDUCT.md"),
6158
Path("CHANGELOG.md"),
62-
Path("docs/")
59+
Path("docs/"),
6360
)
6461

6562

@@ -84,6 +81,7 @@ def sync_uv_with_demo(session: Session) -> None:
8481
external=True,
8582
)
8683

84+
8785
@nox.session(name="uv-in-demo", python=DEFAULT_TEMPLATE_PYTHON_VERSION)
8886
def uv_in_demo(session: Session) -> None:
8987
session.install("cookiecutter", "platformdirs", "loguru", "typer")
@@ -134,21 +132,20 @@ def clear_cache(session: Session) -> None:
134132
def lint(session: Session):
135133
"""Lint the template's own Python files and configurations."""
136134
session.log("Installing linting dependencies for the template source...")
137-
session.run("uv", "sync", "--locked", "--group", "dev", "--group", "lint", external=True)
135+
session.install("-e", ".", "--group", "dev", "--group", "lint")
138136

139-
locations: list[str] = [str(loc) for loc in TEMPLATE_PYTHON_LOCATIONS + TEMPLATE_CONFIG_AND_DOCS]
140137
session.log(f"Running Ruff formatter check on template files with py{session.python}.")
141-
session.run("uv", "run", "ruff", "format", *locations, "--check", external=True)
138+
session.run("ruff", "format")
142139

143140
session.log(f"Running Ruff check on template files with py{session.python}.")
144-
session.run("uv", "run", "ruff", "check", *locations, "--verbose", external=True)
141+
session.run("ruff", "check", "--verbose", "--fix")
145142

146143

147144
@nox.session(python=DEFAULT_TEMPLATE_PYTHON_VERSION)
148145
def docs(session: Session):
149146
"""Build the template documentation website."""
150147
session.log("Installing documentation dependencies for the template docs...")
151-
session.run("uv", "sync", "--locked", "--group", "dev", "--group", "docs", external=True)
148+
session.install("-e", ".", "--group", "dev", "--group", "docs")
152149

153150
session.log(f"Building template documentation with py{session.python}.")
154151
# Set path to allow Sphinx to import from template root if needed (e.g., __version__.py)
@@ -178,7 +175,7 @@ def test(session: Session) -> None:
178175
session.log("Running template tests...")
179176
session.log("Installing template testing dependencies...")
180177
# Sync deps from template's own pyproject.toml, e.g., 'dev' group that includes 'pytest', 'cookiecutter'
181-
session.run("uv", "sync", "--locked", "--group", "dev", "--group", "test", external=True)
178+
session.install("-e", ".", "--group", "dev", "--group", "test")
182179

183180
# Create a temporary directory for the generated project
184181
temp_dir: Path = Path(tempfile.mkdtemp())
@@ -188,19 +185,18 @@ def test(session: Session) -> None:
188185
# Need to find cookiecutter executable - it's in the template dev env installed by uv sync.
189186
cookiecutter_command: list[str] = ["uv", "run", "cookiecutter", "--no-input", "--output-dir", str(temp_dir), "."]
190187

191-
192188
session.run(*cookiecutter_command, external=True)
193189

194190
# Navigate into the generated project directory
195-
generated_project_dir = temp_dir / "test_project" # Use the slug defined in --extra-context
191+
generated_project_dir = temp_dir / "test_project" # Use the slug defined in --extra-context
196192
if not generated_project_dir.exists():
197193
session.error(f"Generated project directory not found: {generated_project_dir}")
198194

199195
session.log(f"Changing to generated project directory: {generated_project_dir}")
200196
session.cd(generated_project_dir)
201197

202198
session.log("Installing generated project dependencies using uv sync...")
203-
session.run("uv", "sync", "--locked", external=True)
199+
session.install("-e", ".", external=True)
204200

205201
session.log("Running generated project's default checks...")
206202
session.run("uv", "run", "nox", external=True)
@@ -236,12 +232,11 @@ def release_template(session: Session):
236232
cz_bump_args = ["uvx", "cz", "bump", "--changelog"]
237233

238234
if increment:
239-
cz_bump_args.append(f"--increment={increment}")
235+
cz_bump_args.append(f"--increment={increment}")
240236

241237
session.log("Running cz bump with args: %s", cz_bump_args)
242238
# success_codes=[0, 1] -> Allows code 1 which means 'nothing to bump' if no conventional commits since last release
243239
session.run(*cz_bump_args, success_codes=[0, 1], external=True)
244240

245241
session.log("Template version bumped and tag created locally via Commitizen/uvx.")
246242
session.log("IMPORTANT: Push commits and tags to remote (`git push --follow-tags`) to trigger CD for the TEMPLATE.")
247-

scripts/generate-demo-project.py

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,12 @@
77
from typing import Annotated
88

99
import typer
10-
1110
from cookiecutter.main import cookiecutter
1211
from typer.models import OptionInfo
1312

13+
1414
FolderOption: partial[OptionInfo] = partial(
15-
typer.Option,
16-
dir_okay=True,
17-
file_okay=False,
18-
resolve_path=True,
19-
path_type=Path
15+
typer.Option, dir_okay=True, file_okay=False, resolve_path=True, path_type=Path
2016
)
2117

2218

@@ -47,7 +43,7 @@ def _remove_any_existing_demo(parent_path: Path) -> None:
4743
def main(
4844
repo_folder: Annotated[Path, FolderOption("--repo-folder", "-r")],
4945
demos_cache_folder: Annotated[Path, FolderOption("--demos-cache-folder", "-c")],
50-
demo_name: Annotated[str, typer.Option("--demo-name", "-d")]
46+
demo_name: Annotated[str, typer.Option("--demo-name", "-d")],
5147
) -> None:
5248
"""Updates the poetry.lock file."""
5349
try:

scripts/prepare-github-release.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ def main(
146146
description from the draft release notes. The branch contains a single
147147
commit which updates the version number in the documentation.
148148
"""
149-
150149
if tag is None:
151150
today = datetime.date.today()
152151
tag = f"{today:%Y.%-m.%-d}"

scripts/sync-uv-with-demo.py

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,9 @@
77
from typing import Annotated
88

99
import typer
10-
10+
from loguru import logger
1111
from typer.models import OptionInfo
1212

13-
from loguru import logger
1413

1514
FolderOption: partial[OptionInfo] = partial(
1615
typer.Option, dir_okay=True, file_okay=False, resolve_path=True, path_type=Path
@@ -22,9 +21,7 @@ def sync_uv_with_demo(template_folder: Path, demos_cache_folder: Path, demo_name
2221
demo_uv_lock_path: Path = _find_uv_lock_path(demo_root)
2322
output_uv_lock_path: Path = _find_uv_lock_path(template_folder)
2423

25-
_copy_uv_lock_from_demo(
26-
demo_uv_lock_path=demo_uv_lock_path, output_uv_lock_path=output_uv_lock_path
27-
)
24+
_copy_uv_lock_from_demo(demo_uv_lock_path=demo_uv_lock_path, output_uv_lock_path=output_uv_lock_path)
2825
logger.info(f"Copied demo from {demo_uv_lock_path=} to {output_uv_lock_path=}.")
2926

3027

@@ -49,13 +46,11 @@ def _find_uv_lock_path(search_root: Path) -> Path:
4946
def main(
5047
template_folder: Annotated[Path, FolderOption("--template-folder", "-t", exists=True)],
5148
demos_cache_folder: Annotated[Path, FolderOption("--demos-cache-folder", "-c", exists=True)],
52-
demo_name: Annotated[str, typer.Option("--demo-name", "-d")]
49+
demo_name: Annotated[str, typer.Option("--demo-name", "-d")],
5350
) -> None:
5451
"""Updates the uv.lock file."""
5552
try:
56-
sync_uv_with_demo(
57-
template_folder=template_folder, demos_cache_folder=demos_cache_folder, demo_name=demo_name
58-
)
53+
sync_uv_with_demo(template_folder=template_folder, demos_cache_folder=demos_cache_folder, demo_name=demo_name)
5954
except Exception as error:
6055
typer.secho(f"error: {error}", fg="red")
6156
sys.exit(1)

tests/conftest.py

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import os
44
import subprocess
5-
65
from pathlib import Path
76
from typing import Generator
87

@@ -25,10 +24,7 @@ def robust_python_demo_path(tmp_path_factory: TempPathFactory) -> Path:
2524
no_input=True,
2625
overwrite_if_exists=True,
2726
output_dir=demos_path,
28-
extra_context={
29-
"project_name": "robust-python-demo",
30-
"add_rust_extension": False
31-
}
27+
extra_context={"project_name": "robust-python-demo", "add_rust_extension": False},
3228
)
3329
path: Path = demos_path / "robust-python-demo"
3430
subprocess.run(["uv", "lock"], cwd=path)
@@ -44,10 +40,7 @@ def robust_maturin_demo_path(tmp_path_factory: TempPathFactory) -> Path:
4440
no_input=True,
4541
overwrite_if_exists=True,
4642
output_dir=demos_path,
47-
extra_context={
48-
"project_name": "robust-maturin-demo",
49-
"add_rust_extension": True
50-
}
43+
extra_context={"project_name": "robust-maturin-demo", "add_rust_extension": True},
5144
)
5245
path: Path = demos_path / "robust-maturin-demo"
5346
subprocess.run(["uv", "sync"], cwd=path)

0 commit comments

Comments
 (0)