Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ To get started:

#### Prerequisites

1. **Python 3.10+**: We recommend using [pyenv](https://github.com/pyenv/pyenv) or
1. **Python 3.11+**: We recommend using [pyenv](https://github.com/pyenv/pyenv) or
[uv](https://docs.astral.sh/uv/) for managing Python versions.
2. **[Pip](https://pip.pypa.io/en/stable/installation/) or [Pipx](https://pipx.pypa.io/stable/)**
3. **[Copier](https://github.com/copier-org/copier)**: Install Copier using pip or pipx.
Expand Down
10 changes: 5 additions & 5 deletions copier.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ repository_visibility:
- internal
- private

repository_slug:
default_module_name:
type: str
help: "Not prompted. This is computed for re-use."
default: "{{ repository_name | lower | replace('-', '_') | replace(' ', '_') }}"
Expand All @@ -85,11 +85,11 @@ is_public_repo:

module_name:
type: str
help: "What is your Python module name? (e.g. app/src/{{ repository_slug }})"
default: "{{ repository_slug }}"
help: "What is your Python module name? (e.g. app / src / {{ default_module_name }})"
default: "{{ default_module_name }}"
validator: >-
{% if not (module_name | regex_search('^[a-z][a-z0-9\_\-]+$')) %}
Must use a lowercase letter followed by one or more of (a-z, 0-9, _, -).
{% if not (module_name | regex_search('^[a-z][a-z0-9_]*$')) %}
Must be a valid Python package name: start with a lowercase letter and use only lowercase letters, numbers, and underscores.
{% endif %}

enable_dependabot_version_updates:
Expand Down
49 changes: 47 additions & 2 deletions tests/test_template_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

from __future__ import annotations

import subprocess
import sys
from pathlib import Path
from typing import Any

Expand All @@ -28,6 +30,16 @@ def read_pre_commit_config(destination: Path) -> str:
return (destination / ".pre-commit-config.yaml").read_text(encoding="utf-8")


def assert_python_files_compile(*paths: Path) -> None:
"""Assert that rendered Python files are syntactically valid."""
subprocess.run(
[sys.executable, "-m", "py_compile", *[str(path) for path in paths]],
check=True,
capture_output=True,
text=True,
)


def assert_public_visibility_outputs(destination: Path) -> None:
"""Assert the public-repository specific files and README content."""
assert (destination / "LICENSE").exists()
Expand Down Expand Up @@ -244,8 +256,6 @@ def test_uv_generation_requires_confirmation(
generated_project_dir: Path,
) -> None:
"""The uv option should reject an explicit decision not to use uv."""
import subprocess

with pytest.raises(subprocess.CalledProcessError) as exc_info:
copier_runner.copy(
generated_project_dir,
Expand All @@ -255,3 +265,38 @@ def test_uv_generation_requires_confirmation(
)

assert "You must confirm the use of uv to continue" in exc_info.value.stderr


def test_valid_custom_module_name_generates_importable_python(
copier_runner: Any,
generated_project_dir: Path,
) -> None:
"""A custom module name using underscores should render valid Python imports."""
copier_runner.copy(
generated_project_dir,
repository_visibility="public",
package_manager="poetry",
module_name="custom_module",
)

assert (generated_project_dir / "custom_module").exists()
assert_python_files_compile(
generated_project_dir / "custom_module" / "__main__.py",
generated_project_dir / "tests" / "unit" / "conftest.py",
)


def test_hyphenated_module_name_is_rejected(
copier_runner: Any,
generated_project_dir: Path,
) -> None:
"""A hyphenated module name should fail validation because it is not import-safe."""
with pytest.raises(subprocess.CalledProcessError) as exc_info:
copier_runner.copy(
generated_project_dir,
repository_visibility="public",
package_manager="poetry",
module_name="bad-name",
)

assert "valid Python package name" in exc_info.value.stderr
Loading