Skip to content

Commit fbec3f4

Browse files
committed
reorg and add templates + readme
1 parent 3dcf4d9 commit fbec3f4

35 files changed

+2954
-160
lines changed

.github/workflows/ci.yml

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Generated by preen — do not edit manually
2+
# Regenerate with: preen sync
3+
4+
name: CI
5+
6+
on:
7+
push:
8+
branches: [main]
9+
pull_request:
10+
branches: [main]
11+
12+
jobs:
13+
test:
14+
runs-on: ${{ matrix.os }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
python-version: ["3.9", "3.10", "3.11", "3.12"]
19+
os: [ubuntu-latest]
20+
21+
steps:
22+
- uses: actions/checkout@v4
23+
- uses: astral-sh/setup-uv@v4
24+
with:
25+
python-version: ${{ matrix.python-version }}
26+
- run: uv sync
27+
- run: uv run pytest
28+
29+
lint:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- uses: actions/checkout@v4
33+
- uses: astral-sh/setup-uv@v4
34+
- run: uv sync
35+
- run: uv run ruff check
36+
- run: uv run ruff format --check

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,6 @@
11
.DS_Store
22
/preen/__pycache__
3+
/tests/__pycache__
4+
/preen/templates/__pycache__
5+
/preen/checks/__pycache__
6+
/preen.egg-info

CITATION.cff

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,10 @@ cff-version: 1.2.0
55
message: "If you use this software, please cite it as below."
66
title: preen
77
version: 0.1.0
8-
date-released: 2025-12-04
9-
url: https://github.com/username/preen
10-
repository-code: https://github.com/username/preen
11-
license: MIT
8+
date-released: 2025-12-03
9+
url: https://github.com/gojiplus/preen
10+
repository-code: https://github.com/gojiplus/preen
1211
authors:
1312
- family-names: Sood
1413
given-names: Gaurav
15-
14+

README.md

Lines changed: 246 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,250 @@
11
# preen
22

3-
*An opinionated, agentic CLI for Python package hygiene and release.*
3+
**An opinionated, agentic CLI for Python package hygiene and release**
44

5-
`preen` helps Python package maintainers keep their metadata, configuration files and workflows in sync. It reads information from your `pyproject.toml` and regenerates derived files such as GitHub Actions workflows, documentation configuration and a `CITATION.cff` file. The tool is intended as the last step before a release to ensure that everything is consistent and ready for publication.
5+
*"Get your feathers in order before you fly"*
66

7-
This repository contains the early implementation of `preen`. The current scope focuses on the sync functionality, which reads a project's metadata and writes a set of standardised files. Future versions will add an interactive check runner, initialisation helpers and release workflows as described in the vision.
7+
`preen` is a comprehensive tool for Python package maintenance that treats `pyproject.toml` as the single source of truth. It automatically generates and synchronizes derived files, runs comprehensive pre-release checks, and provides an opinionated workflow for package development and release.
8+
9+
## Features
10+
11+
- 🔍 **7 comprehensive checks** - linting, tests, dependencies, CI matrix, project structure, version consistency, and citation validation
12+
- 🔧 **Interactive fixes** - preview diffs and apply fixes automatically or selectively
13+
- 📦 **Package initialization** - scaffold new packages with opinionated best practices
14+
- 🔄 **File synchronization** - generate CI workflows, documentation config, and CITATION.cff from pyproject.toml
15+
- 📈 **Version management** - semantic versioning with automatic derived file updates
16+
- 🎯 **Modern tooling** - uv-native workflows, GitHub Actions, and trusted publishing
17+
18+
## Installation
19+
20+
```bash
21+
pip install preen
22+
```
23+
24+
Requires Python 3.9+
25+
26+
## Quick Start
27+
28+
### Create a new package
29+
```bash
30+
preen init mypackage
31+
cd mypackage
32+
pip install -e .[dev]
33+
```
34+
35+
### Run checks and fixes
36+
```bash
37+
preen check # Interactive check with fix prompts
38+
preen check --fix # Apply all fixes automatically
39+
preen check --strict # Exit 1 if any issues (perfect for CI)
40+
```
41+
42+
### Sync derived files
43+
```bash
44+
preen sync # Update all derived files
45+
preen sync --only citation # Update only CITATION.cff
46+
preen sync --check # Check if files need updating (CI mode)
47+
```
48+
49+
### Manage versions
50+
```bash
51+
preen bump patch # 1.0.0 → 1.0.1
52+
preen bump minor # 1.0.1 → 1.1.0
53+
preen bump major # 1.1.0 → 2.0.0
54+
```
55+
56+
## Commands
57+
58+
### `preen init`
59+
Initialize new Python packages with opinionated structure:
60+
- Modern `pyproject.toml` with setuptools backend
61+
- `src/` layout for better import isolation
62+
- Comprehensive `tests/` directory at project root
63+
- GitHub Actions workflows for CI, docs, and release
64+
- Pre-configured development dependencies (pytest, ruff)
65+
- CITATION.cff for academic software
66+
67+
```bash
68+
preen init mypackage # Interactive mode
69+
preen init mypackage --dir ./custom # Specify directory
70+
```
71+
72+
### `preen check`
73+
Run comprehensive pre-release checks:
74+
75+
| Check | Description |
76+
|-------|-------------|
77+
| **ruff** | Code linting and formatting |
78+
| **tests** | Run pytest suite |
79+
| **deps** | Find unused/missing dependencies (requires deptry) |
80+
| **ci-matrix** | Verify CI tests all declared Python versions |
81+
| **structure** | Enforce project structure best practices |
82+
| **version** | Detect hardcoded version strings |
83+
| **citation** | Ensure CITATION.cff matches pyproject.toml |
84+
85+
```bash
86+
preen check # Interactive mode
87+
preen check --fix # Auto-apply all fixes
88+
preen check --only ruff,tests # Run specific checks
89+
preen check --skip deps # Skip dependency check
90+
preen check --strict # CI mode (exit 1 on issues)
91+
```
92+
93+
### `preen sync`
94+
Synchronize derived files from `pyproject.toml`:
95+
- `.github/workflows/ci.yml` - CI matrix from Python classifiers
96+
- `.github/workflows/docs.yml` - Documentation deployment
97+
- `.github/workflows/release.yml` - PyPI publishing with trusted publisher
98+
- `docs/conf.py` - Sphinx configuration
99+
- `CITATION.cff` - Citation metadata for academic software
100+
101+
```bash
102+
preen sync # Update all derived files
103+
preen sync --only ci,citation # Update specific targets
104+
preen sync --check # Verify files are up to date
105+
```
106+
107+
### `preen bump`
108+
Semantic version management:
109+
- Updates version in `pyproject.toml`
110+
- Regenerates all derived files with new version
111+
- Commits changes to git with conventional commit message
112+
113+
```bash
114+
preen bump patch # Bug fixes: 1.0.0 → 1.0.1
115+
preen bump minor # New features: 1.0.1 → 1.1.0
116+
preen bump major # Breaking changes: 1.1.0 → 2.0.0
117+
preen bump patch --dry-run # Preview changes
118+
preen bump minor --no-commit # Skip git commit
119+
```
120+
121+
## Configuration
122+
123+
Customize behavior in `pyproject.toml`:
124+
125+
```toml
126+
[tool.preen]
127+
# CI configuration
128+
ci_os = ["ubuntu-latest", "macos-latest"]
129+
ci_runner = "uv" # or "pip"
130+
131+
# Documentation
132+
sphinx_theme = "furo"
133+
use_myst = true
134+
135+
# Structure preferences
136+
src_layout = true
137+
tests_at_root = true
138+
139+
# Skip specific checks
140+
skip_checks = ["deps", "structure"]
141+
```
142+
143+
## Development Workflow
144+
145+
Typical workflow for package maintenance:
146+
147+
```bash
148+
# 1. Initialize new package
149+
preen init myawesome-package
150+
cd myawesome-package
151+
152+
# 2. Develop your package
153+
# ... write code, tests ...
154+
155+
# 3. Pre-release checks
156+
preen check --fix
157+
158+
# 4. Version bump and release prep
159+
preen bump minor
160+
git push origin main
161+
162+
# 5. Manual steps (for now)
163+
# - Create GitHub release
164+
# - CI will build and publish to PyPI via trusted publisher
165+
```
166+
167+
## Philosophy
168+
169+
**pyproject.toml as Single Source of Truth**
170+
- All metadata lives in one place
171+
- Derived files are generated, never edited manually
172+
- Eliminates version mismatches and configuration drift
173+
174+
**Opinionated Best Practices**
175+
- `src/` layout for better import isolation
176+
- `tests/` at project root, not inside package
177+
- Modern Python packaging (setuptools, trusted publishing)
178+
- Comprehensive CI matrix matching declared Python support
179+
180+
**DRY Across Configuration**
181+
- CI matrix generated from Python classifiers
182+
- Documentation config reflects project metadata
183+
- CITATION.cff stays in sync with authors and version
184+
185+
## Generated Files
186+
187+
When you run `preen sync`, these files are generated/updated:
188+
189+
```
190+
.github/workflows/
191+
├── ci.yml # Test matrix + linting
192+
├── docs.yml # Documentation deployment
193+
└── release.yml # PyPI publishing
194+
195+
docs/
196+
└── conf.py # Sphinx configuration
197+
198+
CITATION.cff # Citation metadata
199+
```
200+
201+
All generated files include a header indicating they're managed by preen:
202+
```yaml
203+
# Generated by preen — do not edit manually
204+
# Regenerate with: preen sync
205+
```
206+
207+
## Integration
208+
209+
**GitHub Actions**
210+
```yaml
211+
# .github/workflows/quality.yml
212+
- name: Package hygiene
213+
run: |
214+
pip install preen
215+
preen check --strict
216+
preen sync --check
217+
```
218+
219+
**Pre-commit Hook**
220+
```yaml
221+
# .pre-commit-config.yaml
222+
repos:
223+
- repo: local
224+
hooks:
225+
- id: preen-check
226+
name: preen check
227+
entry: preen check --strict
228+
language: system
229+
pass_filenames: false
230+
```
231+
232+
## License
233+
234+
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
235+
236+
## Contributing
237+
238+
1. Fork the repository
239+
2. Create a feature branch
240+
3. Make your changes
241+
4. Run `preen check` to ensure code quality
242+
5. Submit a pull request
243+
244+
For development setup:
245+
```bash
246+
git clone https://github.com/gojiplus/preen.git
247+
cd preen
248+
pip install -e .[dev]
249+
preen check
250+
```

preen/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"""
88

99
from importlib.metadata import version as _get_version # type: ignore
10-
from pathlib import Path
10+
1111
from .syncer import sync_project
1212

1313
__all__ = ["__version__", "sync_project"]
@@ -22,4 +22,4 @@ def __getattr__(name: str):
2222
"""
2323
if name == "__version__":
2424
return _get_version(__name__)
25-
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
25+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")

preen/__main__.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
"""Allow preen to be run as a module."""
2+
3+
from .cli import run
4+
5+
if __name__ == "__main__":
6+
run()

preen/checks/__init__.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"""Check framework for preen.
2+
3+
This module provides the base infrastructure for running checks and
4+
managing issues/fixes.
5+
"""
6+
7+
from .base import Check, CheckResult, Issue, Fix, Severity
8+
from .runner import run_checks
9+
10+
__all__ = ["Check", "CheckResult", "Issue", "Fix", "Severity", "run_checks"]

0 commit comments

Comments
 (0)