Skip to content

Commit 0763bb4

Browse files
committed
feat(template): add package scaffold
Start from a small src-layout package with a Click entry point and tests.
1 parent 64fb25a commit 0763bb4

6 files changed

Lines changed: 207 additions & 0 deletions

File tree

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Yujeong
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

pyproject.toml

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
[build-system]
2+
requires = ["hatchling>=1.27.0"]
3+
build-backend = "hatchling.build"
4+
5+
[project]
6+
name = "python-template"
7+
dynamic = ["version"]
8+
description = "A minimal, strict Python project template for real-world applications."
9+
readme = "README.md"
10+
requires-python = ">=3.11"
11+
license = { text = "MIT" }
12+
authors = [
13+
{ name = "Yujeong" },
14+
]
15+
keywords = ["python", "template", "uv", "click", "github-actions"]
16+
classifiers = [
17+
"Development Status :: 3 - Alpha",
18+
"Intended Audience :: Developers",
19+
"License :: OSI Approved :: MIT License",
20+
"Programming Language :: Python :: 3",
21+
"Programming Language :: Python :: 3.11",
22+
"Programming Language :: Python :: 3.12",
23+
"Programming Language :: Python :: 3.13",
24+
"Topic :: Software Development :: Build Tools",
25+
]
26+
dependencies = [
27+
"click>=8.1.8",
28+
]
29+
30+
[project.scripts]
31+
python-template = "python_template.__main__:cli"
32+
33+
[project.urls]
34+
Homepage = "https://github.com/techhouse-looper/python-template"
35+
Repository = "https://github.com/techhouse-looper/python-template"
36+
Issues = "https://github.com/techhouse-looper/python-template/issues"
37+
38+
[dependency-groups]
39+
dev = [
40+
"build>=1.3.0",
41+
"pre-commit>=4.3.0",
42+
"pyright>=1.1.405",
43+
"pytest>=8.4.0",
44+
"pytest-cov>=7.0.0",
45+
"ruff>=0.12.0",
46+
]
47+
48+
[tool.hatch.version]
49+
path = "src/python_template/__about__.py"
50+
51+
[tool.hatch.build.targets.wheel]
52+
packages = ["src/python_template"]
53+
54+
[tool.pytest.ini_options]
55+
addopts = "-ra --strict-config --strict-markers"
56+
testpaths = ["tests"]
57+
58+
[tool.ruff]
59+
line-length = 100
60+
target-version = "py311"
61+
src = ["src", "tests"]
62+
63+
[tool.ruff.lint]
64+
select = [
65+
"ANN",
66+
"ARG",
67+
"B",
68+
"C4",
69+
"D",
70+
"E",
71+
"EM",
72+
"F",
73+
"I",
74+
"N",
75+
"PIE",
76+
"PTH",
77+
"RET",
78+
"RUF",
79+
"SIM",
80+
"T20",
81+
"TC",
82+
"UP",
83+
"W",
84+
]
85+
86+
[tool.ruff.lint.per-file-ignores]
87+
"tests/**/*.py" = ["D100", "D103"]
88+
89+
[tool.ruff.format]
90+
docstring-code-format = true
91+
92+
[tool.ruff.lint.pydocstyle]
93+
convention = "google"
94+
95+
[tool.pyright]
96+
pythonVersion = "3.11"
97+
include = ["src", "tests"]
98+
typeCheckingMode = "strict"
99+
venvPath = "."
100+
venv = ".venv"
101+
102+
[tool.coverage.run]
103+
source = ["python_template"]
104+
branch = true
105+
106+
[tool.coverage.report]
107+
show_missing = true
108+
skip_covered = true

src/python_template/__about__.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"""Package version metadata."""
2+
3+
__version__ = "0.1.0"

src/python_template/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
"""Public package interface for the project template."""
2+
3+
from python_template.__about__ import __version__
4+
5+
__all__ = [
6+
"__version__",
7+
]

src/python_template/__main__.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
"""CLI entry point for the template package."""
2+
3+
import click
4+
5+
from python_template import __version__
6+
7+
DEFAULT_TASKS = (
8+
"uv sync --group dev",
9+
"make check",
10+
"make build",
11+
)
12+
13+
14+
@click.command(help="Show the template version and default tasks.")
15+
def cli() -> None:
16+
"""Print the template version and recommended first commands."""
17+
click.echo(f"python-template {__version__}")
18+
click.echo("Default tasks:")
19+
for task in DEFAULT_TASKS:
20+
click.echo(f"- {task}")
21+
22+
23+
def main() -> None:
24+
"""Run the CLI."""
25+
cli()
26+
27+
28+
if __name__ == "__main__":
29+
main()

tests/test_cli.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
"""CLI regression tests."""
2+
3+
from __future__ import annotations
4+
5+
import subprocess
6+
import sys
7+
8+
from python_template import __version__
9+
10+
11+
def test_module_cli_runs() -> None:
12+
"""Run the module entry point and verify the default guidance output."""
13+
result = subprocess.run(
14+
[sys.executable, "-m", "python_template"],
15+
check=True,
16+
capture_output=True,
17+
text=True,
18+
)
19+
20+
assert "python-template" in result.stdout
21+
assert "make check" in result.stdout
22+
23+
24+
def test_module_cli_help_runs() -> None:
25+
"""Run the module help command."""
26+
result = subprocess.run(
27+
[sys.executable, "-m", "python_template", "--help"],
28+
check=True,
29+
capture_output=True,
30+
text=True,
31+
)
32+
33+
assert "Show the template version and default tasks." in result.stdout
34+
assert "Usage:" in result.stdout
35+
36+
37+
def test_package_exports_version() -> None:
38+
"""Expose the package version at the top level."""
39+
assert __version__ == "0.1.0"

0 commit comments

Comments
 (0)