nuv 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nuv-0.1.0/.github/copilot-instructions.md +65 -0
- nuv-0.1.0/.github/workflows/ci.yml +71 -0
- nuv-0.1.0/.github/workflows/publish-pypi.yml +71 -0
- nuv-0.1.0/.gitignore +765 -0
- nuv-0.1.0/.python-version +1 -0
- nuv-0.1.0/LICENSE +21 -0
- nuv-0.1.0/PKG-INFO +144 -0
- nuv-0.1.0/README.md +119 -0
- nuv-0.1.0/docs/plans/2026-02-24-nuv-design.md +193 -0
- nuv-0.1.0/docs/plans/2026-02-24-nuv-implementation.md +870 -0
- nuv-0.1.0/docs/plans/2026-02-26-two-layer-installation.md +190 -0
- nuv-0.1.0/docs/reviews/2026-02-26-comprehensive-repo-review.md +107 -0
- nuv-0.1.0/pyproject.toml +66 -0
- nuv-0.1.0/src/nuv/__init__.py +0 -0
- nuv-0.1.0/src/nuv/_logging.py +12 -0
- nuv-0.1.0/src/nuv/cli.py +87 -0
- nuv-0.1.0/src/nuv/commands/__init__.py +0 -0
- nuv-0.1.0/src/nuv/commands/new.py +165 -0
- nuv-0.1.0/src/nuv/templates/__init__.py +0 -0
- nuv-0.1.0/src/nuv/templates/script/__init__.py +0 -0
- nuv-0.1.0/src/nuv/templates/script/_logging.py.tpl +12 -0
- nuv-0.1.0/src/nuv/templates/script/gitignore.tpl +9 -0
- nuv-0.1.0/src/nuv/templates/script/main.py.tpl +52 -0
- nuv-0.1.0/src/nuv/templates/script/pyproject.toml.tpl +44 -0
- nuv-0.1.0/src/nuv/templates/script/readme.md.tpl +22 -0
- nuv-0.1.0/src/nuv/templates/script/test_main.py.tpl +5 -0
- nuv-0.1.0/tests/__init__.py +0 -0
- nuv-0.1.0/tests/test_new.py +471 -0
- nuv-0.1.0/uv.lock +308 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
# Copilot Instructions
|
|
2
|
+
|
|
3
|
+
## Project overview
|
|
4
|
+
|
|
5
|
+
`nuv` is a CLI tool that scaffolds opinionated uv-based Python projects. Running `nuv new <name>` creates a fully configured project with argparse, logging, 100% test coverage, ruff linting/formatting, and ty type checking — all green from commit zero.
|
|
6
|
+
|
|
7
|
+
## Tech stack
|
|
8
|
+
|
|
9
|
+
- **Language:** Python 3.14+
|
|
10
|
+
- **Package manager:** [uv](https://docs.astral.sh/uv/)
|
|
11
|
+
- **Testing:** pytest with 100% branch coverage enforced (`pytest-cov`)
|
|
12
|
+
- **Linting/formatting:** [ruff](https://docs.astral.sh/ruff/)
|
|
13
|
+
- **Type checking:** [ty](https://github.com/astral-sh/ty)
|
|
14
|
+
|
|
15
|
+
## Repository layout
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
src/nuv/
|
|
19
|
+
_logging.py # LOG_FORMAT + configure(); single source of logging config
|
|
20
|
+
cli.py # argparse entry point; routes subcommands
|
|
21
|
+
commands/
|
|
22
|
+
new.py # logic for `nuv new`: validate, scaffold, uv sync
|
|
23
|
+
templates/
|
|
24
|
+
script/ # *.tpl files rendered via str.format()
|
|
25
|
+
tests/
|
|
26
|
+
test_new.py # unit tests (100% coverage required)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Development commands
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Install dev dependencies
|
|
33
|
+
uv sync
|
|
34
|
+
|
|
35
|
+
# Run all tests (with coverage)
|
|
36
|
+
uv run pytest
|
|
37
|
+
|
|
38
|
+
# Lint
|
|
39
|
+
uv run ruff check src/ tests/
|
|
40
|
+
|
|
41
|
+
# Format check
|
|
42
|
+
uv run ruff format --check src/ tests/
|
|
43
|
+
|
|
44
|
+
# Type check
|
|
45
|
+
uv run ty check src/
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Coding conventions
|
|
49
|
+
|
|
50
|
+
- All source lives under `src/nuv/`; tests live under `tests/`.
|
|
51
|
+
- 100% branch coverage is enforced — every new code path must have a corresponding test.
|
|
52
|
+
- Use `str.format()` (not f-strings or Jinja) for file templates stored in `src/nuv/templates/`; placeholders use `{name}` syntax, and literal `{`/`}` must be written as `{{`/`}}`.
|
|
53
|
+
- Public functions are typed with PEP 604 union syntax (`X | None`) and return types annotated.
|
|
54
|
+
- Errors are surfaced by raising `ValueError`, `RuntimeError`, or `FileNotFoundError` (for missing templates); the CLI entry point catches these, logs them at ERROR level, and returns exit code 1.
|
|
55
|
+
- Logging is configured once via `_logging.configure()` (defined in `src/nuv/_logging.py`). Each module uses `log = logging.getLogger(__name__)`. `cli.main()` calls `configure(args.log_level)` with a `--log-level` flag (default `WARNING`). Scaffolded projects include an identical `_logging.py` module so the pattern carries forward.
|
|
56
|
+
- Do not use `print()` for user-facing output — use `log.info()` for success messages and `log.error()` for errors.
|
|
57
|
+
- Do not introduce new runtime dependencies without updating `pyproject.toml` and `uv.lock`.
|
|
58
|
+
- Follow ruff lint rules: `E`, `F`, `I`, `UP`, `B`, `SIM`.
|
|
59
|
+
|
|
60
|
+
## Adding a new archetype
|
|
61
|
+
|
|
62
|
+
1. Create `src/nuv/templates/<archetype>/` with the required `.tpl` files (see `script/` as a reference).
|
|
63
|
+
2. Add any new logic to `src/nuv/commands/`.
|
|
64
|
+
3. Wire the archetype in `cli.py` if needed.
|
|
65
|
+
4. Add tests to maintain 100% coverage.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: [main]
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
lint:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Install uv
|
|
16
|
+
uses: astral-sh/setup-uv@v5
|
|
17
|
+
with:
|
|
18
|
+
python-version: "3.14"
|
|
19
|
+
enable-cache: true
|
|
20
|
+
|
|
21
|
+
- name: Sync dependencies
|
|
22
|
+
run: uv sync --frozen
|
|
23
|
+
|
|
24
|
+
- name: Lint
|
|
25
|
+
run: |
|
|
26
|
+
uv run --frozen ruff check src/ tests/
|
|
27
|
+
uv run --frozen ruff format --check src/ tests/
|
|
28
|
+
|
|
29
|
+
- name: Type check
|
|
30
|
+
run: uv run --frozen ty check src/
|
|
31
|
+
|
|
32
|
+
test:
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
strategy:
|
|
35
|
+
fail-fast: false
|
|
36
|
+
matrix:
|
|
37
|
+
python-version: ["3.11", "3.14"]
|
|
38
|
+
steps:
|
|
39
|
+
- uses: actions/checkout@v4
|
|
40
|
+
|
|
41
|
+
- name: Install uv
|
|
42
|
+
uses: astral-sh/setup-uv@v5
|
|
43
|
+
with:
|
|
44
|
+
python-version: ${{ matrix.python-version }}
|
|
45
|
+
enable-cache: true
|
|
46
|
+
|
|
47
|
+
- name: Sync dependencies
|
|
48
|
+
run: uv sync --frozen
|
|
49
|
+
|
|
50
|
+
- name: Test
|
|
51
|
+
run: uv run --frozen pytest
|
|
52
|
+
|
|
53
|
+
- name: Integration smoke test
|
|
54
|
+
if: matrix.python-version == '3.14'
|
|
55
|
+
run: |
|
|
56
|
+
uv run --frozen nuv new smoke-test --at /tmp/smoke-test
|
|
57
|
+
cd /tmp/smoke-test && uv sync --frozen && uv run --frozen pytest
|
|
58
|
+
|
|
59
|
+
- name: Build wheel for distribution smoke tests
|
|
60
|
+
if: matrix.python-version == '3.14'
|
|
61
|
+
run: uv build
|
|
62
|
+
|
|
63
|
+
- name: Tool install smoke test from wheel
|
|
64
|
+
if: matrix.python-version == '3.14'
|
|
65
|
+
run: |
|
|
66
|
+
uv tool install --force-reinstall dist/*.whl
|
|
67
|
+
nuv --help
|
|
68
|
+
|
|
69
|
+
- name: uvx smoke test from wheel
|
|
70
|
+
if: matrix.python-version == '3.14'
|
|
71
|
+
run: uvx --from dist/*.whl nuv --help
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
name: Publish to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- "v*"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
steps:
|
|
13
|
+
- uses: actions/checkout@v4
|
|
14
|
+
|
|
15
|
+
- name: Validate semver version and tag match
|
|
16
|
+
if: github.ref_type == 'tag'
|
|
17
|
+
run: |
|
|
18
|
+
python - <<'PY'
|
|
19
|
+
import os
|
|
20
|
+
import re
|
|
21
|
+
import tomllib
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
|
|
24
|
+
version = tomllib.loads(Path("pyproject.toml").read_text())["project"]["version"]
|
|
25
|
+
if not re.fullmatch(r"\d+\.\d+\.\d+", version):
|
|
26
|
+
raise SystemExit(f"pyproject version must be semver X.Y.Z, got: {version}")
|
|
27
|
+
|
|
28
|
+
tag = os.environ["GITHUB_REF_NAME"]
|
|
29
|
+
if not tag.startswith("v"):
|
|
30
|
+
raise SystemExit(f"release tag must start with 'v', got: {tag}")
|
|
31
|
+
|
|
32
|
+
if tag[1:] != version:
|
|
33
|
+
raise SystemExit(f"tag {tag} does not match project version {version}")
|
|
34
|
+
PY
|
|
35
|
+
|
|
36
|
+
- name: Install uv
|
|
37
|
+
uses: astral-sh/setup-uv@v5
|
|
38
|
+
with:
|
|
39
|
+
python-version: "3.14"
|
|
40
|
+
|
|
41
|
+
- name: Build distributions
|
|
42
|
+
run: uv build
|
|
43
|
+
|
|
44
|
+
- name: Validate distributions
|
|
45
|
+
run: uvx twine check dist/*
|
|
46
|
+
|
|
47
|
+
- name: Upload artifacts
|
|
48
|
+
uses: actions/upload-artifact@v4
|
|
49
|
+
with:
|
|
50
|
+
name: dist
|
|
51
|
+
path: dist/*
|
|
52
|
+
|
|
53
|
+
publish:
|
|
54
|
+
needs: build
|
|
55
|
+
runs-on: ubuntu-latest
|
|
56
|
+
permissions:
|
|
57
|
+
actions: read
|
|
58
|
+
contents: read
|
|
59
|
+
id-token: write
|
|
60
|
+
environment:
|
|
61
|
+
name: pypi
|
|
62
|
+
url: https://pypi.org/p/nuv
|
|
63
|
+
steps:
|
|
64
|
+
- name: Download built artifacts
|
|
65
|
+
uses: actions/download-artifact@v4
|
|
66
|
+
with:
|
|
67
|
+
name: dist
|
|
68
|
+
path: dist
|
|
69
|
+
|
|
70
|
+
- name: Publish package distributions to PyPI
|
|
71
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|