Skip to content

[cli] Scaffold pyproject.toml in init templates (not just requirements.txt) #28

Description

@manish-wekan

Context

nitrostack-py init copies nitrostack/templates/{starter,pizzaz,flight-booking}/ into the new folder (nitrostack/cli/main.py init_projectshutil.copytree).

After init, that folder has no pyproject.toml. The only dependency file is requirements.txt, and it is a single unpinned line:

nitrostack

Same for all three templates:

  • nitrostack/templates/starter/requirements.txt
  • nitrostack/templates/pizzaz/requirements.txt
  • nitrostack/templates/flight-booking/requirements.txt

The TypeScript CLI ships a real package.json with @nitrostack/core / @nitrostack/cli (see typescript/packages/cli/templates/typescript-starter/package.json). Python apps are not a first-class installable project.

This blocks:

  • nitrostack-py install editable install (install.py uses -e . only if pyproject.toml exists; otherwise pip install -r requirements.txt)
  • nitrostack-py validate (looks for [project].dependencies or requirements)
  • nitrostack-py upgrade (prefers rewriting pyproject)
  • nitrostack-py pack (has to synthesize a pyproject from _PYPROJECT_TEMPLATE in nitrostack/cli/pack.py because the app never had one)
  • uv / IDEs / GitHub that expect a PEP 621 project

A follow-up issue covers uv.lock, .python-version, and uv.toml. This issue is pyproject.toml only. Do not block on uv being installed.

SDK itself already has pyproject.toml (requires-python = ">=3.10", setuptools). Do not change the SDK package layout except tests/CLI substitution. Work from develop.

Goal

Every nitrostack-py init project is a PEP 621 project: pyproject.toml with name, version, description, requires-python, and dependencies = ["nitrostack"] (plus template-specific deps if any). Init must substitute the project name/description/author collected in the existing prompts.

Keep requirements.txt in sync or generate it from pyproject so validate does not report a spec mismatch (validators.py compares both when both exist). Simplest: pyproject is source of truth; requirements.txt is nitrostack with the same spec, or drop shipping requirements if validate/install still work with pyproject only (they do). Prefer keeping a one-line requirements.txt matching [project].dependencies so older docs/pack still see it.

Probe

rg -n "requirements.txt|pyproject.toml" nitrostack/templates nitrostack/cli/main.py nitrostack/cli/install.py nitrostack/cli/validators.py nitrostack/cli/upgrade.py nitrostack/cli/pack.py
ls nitrostack/templates/starter nitrostack/templates/pizzaz nitrostack/templates/flight-booking
cat nitrostack/templates/starter/requirements.txt

Read:

  • nitrostack/cli/main.pyinit_project (copytree, .env substitution for SERVER_DESC / SERVER_AUTHOR; no pyproject rewrite today)
  • nitrostack/cli/install.py — pyproject vs requirements branch
  • nitrostack/cli/pack.py_PYPROJECT_TEMPLATE (reuse fields: setuptools, requires-python = ">=3.10")
  • tests/test_cli.py_mini_project still uses requirements-only; test_cli_install.py

Confirm init does not currently replace {name} in copied files other than .env.

Implementation

  1. Add pyproject.toml to all three templates. Minimal shape:
[build-system]
requires = ["setuptools>=61.0.0"]
build-backend = "setuptools.build_meta"

[project]
name = "nitrostack-starter"   # pizzaz / flight-booking: distinct default names
version = "0.1.0"
description = "..."
requires-python = ">=3.10"
dependencies = ["nitrostack"]

[tool.setuptools.packages.find]
where = ["."]
namespaces = true
exclude = ["tests*", ".venv*", "venv*", "node_modules*", "widgets*"]

Use a placeholder the init step rewrites, e.g. name = "PROJECT_NAME" or a small token __PROJECT_NAME__, or write the file in init_project after copytree (like .env). Init already has name, description, author. PEP 503/508: project name must be a valid distribution name (hyphenate, lowercase). If the folder is My App, normalize.

  1. Do not add fake extra runtime deps. Flight-booking OAuth comes through nitrostack. If a template imports something not provided by nitrostack, declare it (grep ^import |^from in that template).

  2. Keep requirements.txt aligned with [project].dependencies (same pin/range). Unpinned nitrostack is OK if pyproject is also unpinned; better: nitrostack>=<current SDK major> if you already have that pattern in upgrade tests (nitrostack>=2.0 in tests/test_cli.py). Match whatever upgrade writes today.

  3. pack should use the project’s pyproject when present instead of always synthesizing _PYPROJECT_TEMPLATE (if that is a one-line change; otherwise leave pack as-is and only ensure init ships pyproject).

  4. Do not require uv in this issue. Do not add uv.lock here (follow-up).

Test / verify

pytest tests/test_cli.py tests/test_cli_install.py -q

Add:

  1. After copying a template dir (or calling init_project with mocked prompts), assert pyproject.toml exists and [project].dependencies contains nitrostack.
  2. install_dependencies(cwd=that_dir) takes the pyproject path (-e .), not only -r requirements.txt. Mock pip like tests/test_cli_install.py.
  3. validate on a fresh template tree does not say nitrostack is missing.
  4. Parametrize all three template names: python-starter, python-pizzaz, python-oauth.
  5. Init substitution: generated name = in pyproject matches the project directory name (normalized).

Manual: nitrostack-py init /tmp/ns-uv-probe --template python-starter (non-interactive if flags exist; otherwise unit-test the copy+rewrite function). Folder must contain pyproject.toml. python -m pip install -e /tmp/ns-uv-probe must see a name/version (can mock).

Review

  • Templates stay copyable; no SDK publish change.
  • Name normalization is documented (what happens to spaces/uppercase).
  • requirements.txt and pyproject do not disagree (validate’s mismatch check).

Success

  • All three init templates include pyproject.toml
  • Init rewrites project name (and description if stored)
  • nitrostack-py install on a fresh init uses editable pyproject install
  • validate / upgrade work on the generated tree
  • Tests cover three templates; no live PyPI required

Related

Follow-up: uv.lock / .python-version / uv.toml (file separately). Independent of mcp-2026 issues #22#27.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions