new: port the python template bodies to manifests
CI / build (push) Failing after 2m55s
CI / test (push) Skipped
CI / snap (push) Skipped

This commit is contained in:
2026-09-18 15:20:22 +02:00
parent fa399f64b2
commit 0235ec6457
5 changed files with 80 additions and 62 deletions
+5
View File
@@ -0,0 +1,5 @@
"""Placeholder for {name}, generated by `pkh new`."""
def main() -> None:
print("Hello from {command}!")
+15 -7
View File
@@ -1,9 +1,13 @@
## The `python` template: a PEP 517 project built with pybuild. The logic
## half — the pyproject.toml/setup.py probe, the skeleton bodies and the
## Build-Depends/architecture resolution for existing projects (backend
## package, pyproject presence, C-extension hints) — lives in
## src/new/templates/python.rs; the lists below are the fresh-skeleton
## baseline it starts from.
## The `python` template: a PEP 517 project built with pybuild. The
## skeleton bodies below are static data on the fresh-skeleton baseline
## (the setuptools backend): the module directory and the console-script
## entry point are named by the `{module_name}` placeholder python.rs
## derives from the package name — dpkg names may carry `+`/`.` and may
## start with a digit, none of which a Python module name may. The logic
## half — the pyproject.toml/setup.py probe and the Build-Depends /
## architecture resolution for existing projects (backend package,
## pyproject presence, C-extension hints) — lives in
## src/new/templates/python.rs.
##
## Schema: see src/new/templates/mod.rs.
@@ -18,4 +22,8 @@ build_depends:
- python3-setuptools
architecture: all
rules_dh_line: "dh $@ --with python3 --buildsystem=pybuild"
files: []
files:
- path: pyproject.toml
template: pyproject.toml.tpl
- path: "{module_name}/__init__.py"
template: __init__.py.tpl
+12
View File
@@ -0,0 +1,12 @@
[build-system]
requires = ["setuptools"]
build-backend = "setuptools.build_meta"
[project]
name = "{name}"
version = "{upstream_version}"
description = "{summary}"
requires-python = ">=3.8"
[project.scripts]
{command} = "{module_name}:main"
+10 -1
View File
@@ -356,7 +356,16 @@ static TEMPLATE_SOURCES: &[TemplateSources] = &[
TemplateSources {
id: TemplateId::PYTHON,
manifest: include_str!("../../../data/templates/python/manifest.yml"),
tpls: &[],
tpls: &[
(
"pyproject.toml.tpl",
include_str!("../../../data/templates/python/pyproject.toml.tpl"),
),
(
"__init__.py.tpl",
include_str!("../../../data/templates/python/__init__.py.tpl"),
),
],
hooks: Some(&python::HOOKS),
},
TemplateSources {
+38 -54
View File
@@ -4,18 +4,18 @@
//! …`) with a deliberately minimal line-oriented reader (see
//! [`read_pyproject`]) — pkh has no TOML dependency, and only a handful of
//! keys matter here. A bare `setup.py`/`setup.cfg` project falls back to
//! setuptools without the `pybuild-plugin-pyproject` helper. The manifest's
//! Build-Depends/architecture are the fresh-skeleton baseline the hooks
//! here resolve for an existing project (backend package, pyproject
//! presence, C-extension hints); the skeleton bodies stay in Rust until
//! they move into the manifest's `files:` list (the module name of
//! `[project.scripts]` is derived, not substituted).
//! setuptools without the `pybuild-plugin-pyproject` helper. The skeleton
//! bodies are manifest data (`data/templates/python/manifest.yml`),
//! named by the `{module_name}` placeholder this module derives from the
//! package name; the manifest's Build-Depends/architecture are the
//! fresh-skeleton baseline the hooks here resolve for an existing project
//! (backend package, pyproject presence, C-extension hints).
use std::path::Path;
use regex::Regex;
use super::{OutputFile, ProbeResult, TemplateHooks, source_dir_of};
use super::{ProbeResult, TemplateHooks, source_dir_of};
use crate::new::options::NewOptions;
/// The logic half of the python template.
@@ -122,46 +122,12 @@ fn c_extension_hints(opts: &NewOptions) -> bool {
}
impl TemplateHooks for Hooks {
/// A minimal setuptools-based `pyproject.toml` with one console script,
/// plus the one-module package providing it.
fn skeleton_files(&self, opts: &NewOptions) -> Vec<OutputFile> {
let module = module_name(opts);
vec![
OutputFile::new(
"pyproject.toml",
format!(
"[build-system]\n\
requires = [\"setuptools\"]\n\
build-backend = \"setuptools.build_meta\"\n\
\n\
[project]\n\
name = \"{name}\"\n\
version = \"{version}\"\n\
description = \"{summary}\"\n\
requires-python = \">=3.8\"\n\
\n\
[project.scripts]\n\
{command} = \"{module}:main\"\n",
name = opts.name,
version = opts.upstream_version,
summary = opts.summary,
command = opts.command,
module = module,
),
),
OutputFile::new(
format!("{module}/__init__.py"),
format!(
"\"\"\"Placeholder for {name}, generated by `pkh new`.\"\"\"\n\
\n\
\n\
def main() -> None:\n\
\x20 print(\"Hello from {command}!\")\n",
name = opts.name,
command = opts.command,
),
),
]
/// The `{module_name}` value of the manifest's skeleton bodies (see
/// [`module_name`]): the derived Python identifier naming the skeleton
/// package directory and the console-script entry point of
/// `pyproject.toml`.
fn context(&self, opts: &NewOptions) -> Vec<(String, String)> {
vec![("module_name".to_string(), module_name(opts))]
}
/// Amend the manifest's Build-Depends (the fresh-skeleton baseline)
@@ -385,23 +351,41 @@ mod tests {
"dh $@ --with python3 --buildsystem=pybuild"
);
// Skeleton (manifest data): pyproject.toml + the module package,
// byte-exact.
let skeleton = template.skeleton(&o);
assert_eq!(skeleton.len(), 2);
let pyproject = skeleton
.iter()
.find(|f| f.path == "pyproject.toml")
.expect("pyproject skeleton");
assert!(
pyproject
.contents
.contains("build-backend = \"setuptools.build_meta\"")
assert_eq!(
pyproject.contents,
"[build-system]\n\
requires = [\"setuptools\"]\n\
build-backend = \"setuptools.build_meta\"\n\
\n\
[project]\n\
name = \"mytool\"\n\
version = \"0.1.0\"\n\
description = \"A tool\"\n\
requires-python = \">=3.8\"\n\
\n\
[project.scripts]\n\
mytool = \"mytool:main\"\n"
);
assert!(pyproject.contents.contains("name = \"mytool\""));
assert!(pyproject.contents.contains("mytool = \"mytool:main\""));
let module = skeleton
.iter()
.find(|f| f.path == "mytool/__init__.py")
.expect("module skeleton");
assert!(module.contents.contains("def main()"));
assert_eq!(
module.contents,
"\"\"\"Placeholder for mytool, generated by `pkh new`.\"\"\"\n\
\n\
\n\
def main() -> None:\n\
\x20 print(\"Hello from mytool!\")\n"
);
}
/// dpkg names may carry `+`/`.` and start with a digit — none of which a