Skip to content

Commit ca9a085

Browse files
authored
Merge pull request #14
General Dev Tooling Improvements
2 parents 44a2444 + f3f07b3 commit ca9a085

File tree

6 files changed

+35
-66
lines changed

6 files changed

+35
-66
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ build/ # Build artifacts from setuptools/build backends
3434
.pytest_cache/ # Pytest cache directory
3535
htmlcov/ # Coverage HTML reports (default output dir)
3636
.coverage* # Coverage data files (default name pattern)
37+
coverage.*
3738
test-results/ # Directory for JUnit/Coverage XML reports (as configured in noxfile)
3839

3940
# Editor/IDE specific files

noxfile.py

Lines changed: 9 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,8 @@
4242
)
4343

4444

45-
MATCH_GENERATED_PRECOMMIT_SCRIPT: Path = SCRIPTS_FOLDER / "match-generated-precommit.py"
46-
MATCH_GENERATED_PRECOMMIT_OPTIONS: tuple[str, ...] = GENERATE_DEMO_PROJECT_OPTIONS
45+
LINT_FROM_DEMO_SCRIPT: Path = SCRIPTS_FOLDER / "lint-from-demo.py"
46+
LINT_FROM_DEMO_OPTIONS: tuple[str, ...] = GENERATE_DEMO_PROJECT_OPTIONS
4747

4848

4949
@nox.session(name="generate-demo-project", python=DEFAULT_TEMPLATE_PYTHON_VERSION)
@@ -53,7 +53,7 @@ def generate_demo_project(session: Session) -> None:
5353
session.run("python", GENERATE_DEMO_PROJECT_SCRIPT, *GENERATE_DEMO_PROJECT_OPTIONS, *session.posargs)
5454

5555

56-
@nox.session(name="clear-cache", python=DEFAULT_TEMPLATE_PYTHON_VERSION)
56+
@nox.session(name="clear-cache", python=None)
5757
def clear_cache(session: Session) -> None:
5858
"""Clear the cache of generated project demos.
5959
@@ -68,7 +68,7 @@ def clear_cache(session: Session) -> None:
6868
def lint(session: Session):
6969
"""Lint the template's own Python files and configurations."""
7070
session.log("Installing linting dependencies for the template source...")
71-
session.install("-e", ".", "--group", "dev", "--group", "lint")
71+
session.install("-e", ".", "--group", "lint")
7272

7373
session.log(f"Running Ruff formatter check on template files with py{session.python}.")
7474
session.run("ruff", "format")
@@ -77,19 +77,19 @@ def lint(session: Session):
7777
session.run("ruff", "check", "--verbose", "--fix")
7878

7979

80-
@nox.session(python=DEFAULT_TEMPLATE_PYTHON_VERSION, name="match-generated-precommit", tags=[])
81-
def match_generated_precommit(session: Session):
80+
@nox.session(python=DEFAULT_TEMPLATE_PYTHON_VERSION, name="lint-from-demo", tags=[])
81+
def lint_from_demo(session: Session):
8282
"""Lint the generated project's Python files and configurations."""
8383
session.log("Installing linting dependencies for the generated project...")
8484
session.install("-e", ".", "--group", "dev", "--group", "lint")
85-
session.run("python", MATCH_GENERATED_PRECOMMIT_SCRIPT, *MATCH_GENERATED_PRECOMMIT_OPTIONS, *session.posargs)
85+
session.run("python", LINT_FROM_DEMO_SCRIPT, *LINT_FROM_DEMO_OPTIONS, *session.posargs)
8686

8787

8888
@nox.session(python=DEFAULT_TEMPLATE_PYTHON_VERSION)
8989
def docs(session: Session):
9090
"""Build the template documentation website."""
9191
session.log("Installing documentation dependencies for the template docs...")
92-
session.install("-e", ".", "--group", "dev", "--group", "docs")
92+
session.install("-e", ".", "--group", "docs")
9393

9494
session.log(f"Building template documentation with py{session.python}.")
9595
# Set path to allow Sphinx to import from template root if needed (e.g., __version__.py)
@@ -120,33 +120,8 @@ def test(session: Session) -> None:
120120
session.log("Installing template testing dependencies...")
121121
# Sync deps from template's own pyproject.toml, e.g., 'dev' group that includes 'pytest', 'cookiecutter'
122122
session.install("-e", ".", "--group", "dev", "--group", "test")
123+
session.run("pytest", "tests")
123124

124-
# Create a temporary directory for the generated project
125-
temp_dir: Path = Path(tempfile.mkdtemp())
126-
session.log(f"Rendering template into temporary directory: {temp_dir}")
127-
128-
# Run cookiecutter to generate a project
129-
# Need to find cookiecutter executable - it's in the template dev env installed by uv sync.
130-
cookiecutter_command: list[str] = ["uv", "run", "cookiecutter", "--no-input", "--output-dir", str(temp_dir), "."]
131-
132-
session.run(*cookiecutter_command, external=True)
133-
134-
# Navigate into the generated project directory
135-
generated_project_dir = temp_dir / "test_project" # Use the slug defined in --extra-context
136-
if not generated_project_dir.exists():
137-
session.error(f"Generated project directory not found: {generated_project_dir}")
138-
139-
session.log(f"Changing to generated project directory: {generated_project_dir}")
140-
session.cd(generated_project_dir)
141-
142-
session.log("Installing generated project dependencies using uv sync...")
143-
session.install("-e", ".", external=True)
144-
145-
session.log("Running generated project's default checks...")
146-
session.run("nox")
147-
148-
session.log(f"Cleaning up temporary directory: {temp_dir}")
149-
shutil.rmtree(temp_dir)
150125

151126

152127
@nox.session(venv_backend="none")
Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515

1616

1717
@cli.callback(invoke_without_command=True)
18-
def match_generated_precommit(
18+
def lint_from_demo(
1919
repo_folder: Annotated[Path, FolderOption("--repo-folder", "-r")],
2020
demos_cache_folder: Annotated[Path, FolderOption("--demos-cache-folder", "-c")],
2121
demo_name: Annotated[str, typer.Option("--demo-name", "-d")],
@@ -30,8 +30,10 @@ def match_generated_precommit(
3030
no_cache=no_cache
3131
) as demo_path:
3232
pre_commit.main.main(["run", "--all-files", "--hook-stage=manual", "--show-diff-on-failure"])
33-
retrocookie(instance_path=demo_path, commits=["HEAD"])
34-
git("checkout", "HEAD", "--", "{{cookiecutter.project_name}}/pyproject.toml")
33+
try:
34+
retrocookie(instance_path=demo_path, commits=["HEAD"])
35+
finally:
36+
git("checkout", "HEAD", "--", "{{cookiecutter.project_name}}/pyproject.toml")
3537
except Exception as error:
3638
typer.secho(f"error: {error}", fg="red")
3739
sys.exit(1)

{{cookiecutter.project_name}}/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ build/ # Build artifacts from setuptools/build backends
3636
.pytest_cache/ # Pytest cache directory
3737
htmlcov/ # Coverage HTML reports (default output dir)
3838
.coverage* # Coverage data files (default name pattern)
39+
coverage.*
3940
test-results/ # Directory for JUnit/Coverage XML reports (as configured in noxfile)
4041

4142
# Editor/IDE specific files

{{cookiecutter.project_name}}/noxfile.py

Lines changed: 17 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -71,14 +71,11 @@ def precommit(session: Session) -> None:
7171
activate_virtualenv_in_precommit_hooks(session)
7272

7373

74-
@nox.session(python=DEFAULT_PYTHON_VERSION, name="format-python", tags=[FORMAT, PYTHON])
74+
@nox.session(python=None, name="format-python", tags=[FORMAT, PYTHON])
7575
def format_python(session: Session) -> None:
7676
"""Run Python code formatter (Ruff format)."""
77-
session.log("Installing formatting dependencies...")
78-
session.install("-e", ".", "--group", "dev")
79-
8077
session.log(f"Running Ruff formatter check with py{session.python}.")
81-
session.run("ruff", "format", *session.posargs)
78+
session.run("uvx", "ruff", "format", *session.posargs)
8279

8380

8481
{% if cookiecutter.add_rust_extension == "y" -%}
@@ -92,14 +89,11 @@ def format_rust(session: Session) -> None:
9289

9390

9491
{% endif -%}
95-
@nox.session(python=DEFAULT_PYTHON_VERSION, name="lint-python", tags=[LINT, PYTHON])
92+
@nox.session(python=None, name="lint-python", tags=[LINT, PYTHON])
9693
def lint_python(session: Session) -> None:
9794
"""Run Python code linters (Ruff check, Pydocstyle rules)."""
98-
session.log("Installing linting dependencies...")
99-
session.install("-e", ".", "--group", "dev")
100-
10195
session.log(f"Running Ruff check with py{session.python}.")
102-
session.run("ruff", "check", "--fix", "--verbose")
96+
session.run("uvx", "ruff", "check", "--fix", "--verbose")
10397

10498

10599
{% if cookiecutter.add_rust_extension == "y" -%}
@@ -117,23 +111,20 @@ def lint_rust(session: Session) -> None:
117111
def typecheck(session: Session) -> None:
118112
"""Run static type checking (Pyright) on Python code."""
119113
session.log("Installing type checking dependencies...")
120-
session.install("-e", ".", "--group", "dev")
114+
session.install("pyright")
121115

122116
session.log(f"Running Pyright check with py{session.python}.")
123117
session.run("pyright")
124118

125119

126-
@nox.session(python=DEFAULT_PYTHON_VERSION, name="security-python", tags=[SECURITY, PYTHON, CI])
120+
@nox.session(python=None, name="security-python", tags=[SECURITY, PYTHON, CI])
127121
def security_python(session: Session) -> None:
128122
"""Run code security checks (Bandit) on Python code."""
129-
session.log("Installing security dependencies...")
130-
session.install("-e", ".", "--group", "dev")
131-
132123
session.log(f"Running Bandit static security analysis with py{session.python}.")
133-
session.run("bandit", "-r", PACKAGE_NAME, "-c", "bandit.yml", "-ll")
124+
session.run("uvx", "bandit", "-r", PACKAGE_NAME, "-c", "bandit.yml", "-ll")
134125

135126
session.log(f"Running pip-audit dependency security check with py{session.python}.")
136-
session.run("pip-audit")
127+
session.run("uvx", "pip-audit")
137128

138129

139130
{% if cookiecutter.add_rust_extension == 'y' -%}
@@ -155,11 +146,12 @@ def tests_python(session: Session) -> None:
155146
session.log(f"Running test suite with py{session.python}.")
156147
test_results_dir = Path("test-results")
157148
test_results_dir.mkdir(parents=True, exist_ok=True)
158-
junitxml_file = test_results_dir / f"test-results-py{session.python}.xml"
149+
junitxml_file = test_results_dir / f"test-results-py{session.python.replace('.', '')}.xml"
159150

160151
session.run(
161152
"pytest",
162153
"--cov={}".format(PACKAGE_NAME),
154+
"--cov-append",
163155
"--cov-report=term",
164156
"--cov-report=xml",
165157
f"--junitxml={junitxml_file}",
@@ -201,7 +193,7 @@ def build_python(session: Session) -> None:
201193
{% if cookiecutter.add_rust_extension == "y" -%}
202194
session.run("maturin", "develop", "--uv")
203195
{% else -%}
204-
session.run("uv", "build", "--sdist", "--wheel", "--outdir", "dist/", external=True)
196+
session.run("uv", "build", "--sdist", "--wheel", "--out-dir", "dist/", external=True)
205197
{% endif -%}
206198

207199
session.log("Built packages in ./dist directory:")
@@ -248,17 +240,15 @@ def build_container(session: Session) -> None:
248240
session.log(f"Container image {project_image_name}:latest built locally.")
249241

250242

251-
@nox.session(python=DEFAULT_PYTHON_VERSION, name="publish-python", tags=[RELEASE])
243+
@nox.session(python=None, name="publish-python", tags=[RELEASE])
252244
def publish_python(session: Session) -> None:
253245
"""Publish sdist and wheel packages to PyPI via uv publish.
254246
255247
Requires packages to be built first (`nox -s build-python` or `nox -s build`).
256248
Requires TWINE_USERNAME/TWINE_PASSWORD or TWINE_API_KEY environment variables set (usually in CI).
257249
"""
258-
session.install("twine")
259-
260250
session.log("Checking built packages with Twine.")
261-
session.run("twine", "check", "dist/*")
251+
session.run("uvx", "twine", "check", "dist/*")
262252

263253
session.log("Publishing packages to PyPI.")
264254
session.run("uv", "publish", "dist/*", external=True)
@@ -275,7 +265,7 @@ def publish_rust(session: Session) -> None:
275265

276266

277267
{% endif -%}
278-
@nox.session(venv_backend="none", tags=[RELEASE])
268+
@nox.session(python=None, tags=[RELEASE])
279269
def release(session: Session) -> None:
280270
"""Run the release process using Commitizen.
281271
@@ -290,15 +280,15 @@ def release(session: Session) -> None:
290280
session.skip("Git not available.")
291281

292282
session.log("Checking Commitizen availability via uvx.")
293-
session.run("cz", "--version", success_codes=[0])
283+
session.run("uvx", "--from=commitizen", "cz", "version", success_codes=[0])
294284

295285
increment = session.posargs[0] if session.posargs else None
296286
session.log(
297287
"Bumping version and tagging release (increment: %s).",
298288
increment if increment else "default",
299289
)
300290

301-
cz_bump_args = ["uvx", "cz", "bump", "--changelog"]
291+
cz_bump_args = ["uvx", "--from=commitizen", "cz", "bump", "--changelog"]
302292

303293
if increment:
304294
cz_bump_args.append(f"--increment={increment}")
@@ -310,7 +300,7 @@ def release(session: Session) -> None:
310300
session.log("IMPORTANT: Push commits and tags to remote (`git push --follow-tags`) to trigger CD pipeline.")
311301

312302

313-
@nox.session(venv_backend="none")
303+
@nox.session(python=None)
314304
def tox(session: Session) -> None:
315305
"""Run the 'tox' test matrix.
316306

{{cookiecutter.project_name}}/pyproject.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ description = "{{cookiecutter.project_name}}"
55
authors = [
66
{ name = "{{cookiecutter.author}}", email = "{{cookiecutter.email}}" },
77
]
8-
license = { text = "{{cookiecutter.license}}" }
8+
license = "{{cookiecutter.license}}"
9+
license-files = ["LICENSE"]
910
readme = "README.md"
1011
requires-python = ">={{cookiecutter.min_python_version}},<4.0"
1112
keywords = [
@@ -14,7 +15,6 @@ keywords = [
1415
classifiers = [
1516
"Programming Language :: Python :: {{cookiecutter.min_python_version}}",
1617
"Programming Language :: Python :: 3 :: Only",
17-
"License :: OSI Approved :: {{cookiecutter.license}}",
1818
]
1919
dependencies = [
2020
"loguru>=0.7.3",

0 commit comments

Comments
 (0)