Skip to content

Commit 28c95af

Browse files
authored
Merge pull request #41 from DHI/package-standards
Add distilled package standards page and review skill
2 parents 4c83a91 + 63e17e3 commit 28c95af

7 files changed

Lines changed: 726 additions & 15 deletions

File tree

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
---
2+
name: review-python-package
3+
description: Audit a Python package repository against the DHI Python package standards — layout, pyproject, dependencies, tests, code smells, docs, CI and release setup. Produces a findings report with links to the rule each finding breaks, and offers to open GitHub issues. Use when asked to review, audit or health-check a Python package or repo, or asked "is this a proper package yet".
4+
---
5+
6+
# Review a Python package
7+
8+
Audit a whole repository against the DHI Python package standards. This is a repository
9+
audit — it judges the package as it stands, not a single change. If asked to review a pull
10+
request or a diff, review only the changed files against the same standards.
11+
12+
## Standards
13+
14+
The rules live in `standards.md` at the root of the `python-package-development` repository,
15+
published at:
16+
17+
```
18+
https://dhi.github.io/python-package-development/standards.html
19+
```
20+
21+
Read the local file if this skill is running inside that repository
22+
(`../../../standards.md` from this skill's directory); otherwise fetch the published page.
23+
**Read it before reviewing** — do not audit from memory. Every rule carries a severity
24+
(*Blocker* / *Recommended* / *Nice*) and its heading is the anchor you cite.
25+
26+
## Gather evidence
27+
28+
Work from what the repository actually contains. Do not guess at numbers you can measure.
29+
30+
The reviewer may be on Windows without a POSIX shell, so use the Glob, Read and Grep tools
31+
for anything that inspects files — never `ls`, `cat`, or a pipe into `grep`.
32+
33+
| What | How |
34+
| --- | --- |
35+
| Layout, `.gitignore`, `LICENSE`, `README` | Glob `*` and `.*` at the root |
36+
| Build system, metadata, dependencies, versioning | Read `pyproject.toml` |
37+
| CI | Glob `.github/workflows/*`, then Read each |
38+
| Data committed to git | `git ls-files "*.csv" "*.nc" "*.dfs*" "*.xlsx" "*.zip" "*.parquet"` |
39+
| Commit hygiene | `git log --oneline -20` |
40+
41+
Then run the linter — ground truth, not a guess. `uvx` so it works without the repository's
42+
environment installed:
43+
44+
```bash
45+
uvx ruff check .
46+
uvx ruff format --check .
47+
```
48+
49+
`ruff` reads the repository's `[tool.ruff]` config if there is one. If there is none you are
50+
seeing the default ruleset, which is not the same as the project's intent — say so in the
51+
report rather than presenting the output as the project's own standard.
52+
53+
Then read the source: `src/` (or the package directory), `tests/`, `docs/`.
54+
55+
**Do not run** `pytest`, `mypy` or `uv sync` on your own initiative — they are slow, may need
56+
network or credentials, and an unfamiliar test suite may have side effects. Report what the
57+
test suite looks like and offer to run it. Whether a type checker runs at all is visible in
58+
the workflow file — judge that from reading it, not by running one.
59+
60+
## Check for the code smells the course names
61+
62+
Search as a starting point, then read the hits — a match is a candidate, not a finding.
63+
64+
Use the Grep tool over `**/*.py`, showing line numbers. These are regular expressions for
65+
that tool, not shell commands — do not wrap them in `grep`, and do not escape the `|`.
66+
67+
```
68+
def .*=\s*(\[\]|\{\}|set\(\)|dict\(\)|list\(\)) # mutable default arguments
69+
except\s*: # bare except
70+
except.*:\s*pass # swallowed error, one-line form
71+
def [a-z]+[A-Z] # java-like API
72+
\w+\.\w*\._[a-z] # reaching into another object's internals
73+
```
74+
75+
`except.*:\s*pass` only catches the one-line form, so read every `except` block you find. For
76+
the last pattern, discard the `self._` hits — those are the class's own internals.
77+
78+
The rest have no pattern worth writing; read for them:
79+
80+
| Rule | What to look for |
81+
| --- | --- |
82+
| Class variables that should be instance variables | mutable assignment in a class body, outside `__init__` |
83+
| Modified input arguments | assignment to a parameter's elements inside a function |
84+
| Mixed return types | multiple `return` statements of different types in one function |
85+
| Missing docstrings | public functions and classes with no `"""` |
86+
| Removals with no deprecation path | `git log -p` on the public API vs `CHANGELOG.md` |
87+
88+
## Report
89+
90+
Print the report in the conversation. Do not write a file unless asked.
91+
92+
- One-line verdict first — is this a package someone can install and depend on, or not.
93+
- Then **Blockers**, **Recommended**, **Nice** in that order. Omit empty sections.
94+
- Every finding: `file:line` where there is one, what is wrong in one line, the fix, and the
95+
anchor URL of the rule. `✗` for Blockers, `⚠` for everything else.
96+
- Say what you checked and found clean — a short "✓ Packaging, docs, CI" line. Silence reads
97+
as "not checked".
98+
- Report what you did not check and why (tests not run, package not installed).
99+
100+
```
101+
**my_library** — not installable yet
102+
103+
Blockers
104+
✗ pyproject.toml — no [build-system], so pip cannot build this
105+
https://dhi.github.io/python-package-development/standards.html#pyproject.toml
106+
✗ No LICENSE — effectively all rights reserved, colleagues cannot legally use it
107+
https://dhi.github.io/python-package-development/standards.html#license
108+
✗ src/clean.py:22 — mutable default `cart=[]` is shared across every call; use None
109+
https://dhi.github.io/python-package-development/standards.html#mutable-default-arguments
110+
111+
Recommended
112+
⚠ No .github/workflows/ — tests never run outside your machine
113+
https://dhi.github.io/python-package-development/standards.html#ci-on-every-push-and-pull-request
114+
115+
✓ Clean: layout, README, naming, dependency groups
116+
Not checked: test suite not run (offer: `uv run pytest`)
117+
```
118+
119+
Do not pad the report. A package that is in good shape gets a short report saying so.
120+
121+
## Afterwards
122+
123+
Offer, do not act:
124+
125+
- Open a GitHub issue per blocker (`gh issue create`) — **ask first, and confirm the target
126+
repository**. Creating issues is outward-facing.
127+
- Run the test suite, or `mypy`.
128+
- Fix the findings.

‎03_testing.qmd‎

Lines changed: 24 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -502,33 +502,43 @@ Line # Hits Time Per Hit % Time Line Contents
502502
19 1 500.0 500.0 0.0 return points
503503
```
504504

505-
## Makefiles {.smaller}
505+
## Task runners {.smaller}
506506

507507
::: {.incremental}
508-
* Makefiles simplify running complex commands.
509-
* They act as a single source of truth for how to run your tools.
510-
* Self documenting, making it easier to onboard new team members.
511-
* Run 'make <command>' to run a command from the Makefile.
512-
* On Linux by default, for Windows install with [MSYS2](https://www.msys2.org/) or [Chocolatey](https://chocolatey.org/) (or use WSL).
508+
* A task runner simplifies running complex commands.
509+
* It acts as a single source of truth for how to run your tools.
510+
* Self documenting, making it easier to onboard new team members — and for coding agents to find the right command.
511+
* We use [`just`](https://just.systems): one cross-platform binary, install with `uv tool install rust-just`.
512+
* Run `just <recipe>`, and `just --list` to see what is available.
513+
* On Windows, `set windows-shell` makes the recipes run in PowerShell.
514+
* `make` does the same job, but is not installed on Windows and is fussy about tabs.
513515
:::
514516

515517
. . .
516518

517-
Example
519+
From the [DHI python template](https://github.com/DHI/template-python-library)
518520

519-
```{.makefile filename="Makefile" code-line-numbers="|1|5-6|8-9|11-12|3|"}
520-
LIB = my_library
521+
```{.just filename="justfile" code-line-numbers="|1|3|5|7-14|16-20|"}
522+
set windows-shell := ["powershell.exe", "-NoLogo", "-Command"]
521523
522-
check: lint typecheck test
524+
LIB := "my_library"
525+
526+
check: lint typecheck test doctest
523527
524528
lint:
525-
ruff check $(LIB)
529+
uv run ruff check {{LIB}}
526530
527531
format:
528-
ruff format $(LIB)
532+
uv run ruff format {{LIB}}
529533
530534
test:
531-
pytest --disable-warnings
535+
uv run pytest --disable-warnings
536+
537+
typecheck:
538+
uv run mypy {{LIB}}/ --config-file pyproject.toml
539+
540+
doctest:
541+
uv run pytest --doctest-modules {{LIB}}
532542
```
533543

534544
## Summary {.smaller}
@@ -544,6 +554,6 @@ test:
544554
* **Ruff** is a fast linter that checks for common errors and style issues.
545555
* **Ruff** is also an automatic code formatter that enforces a consistent style.
546556
* Profiling is a way to measure the performance of your code.
547-
* **Makefiles** simplify project related commands for everyone.
557+
* **Task runners** like **just** simplify project related commands for everyone.
548558

549559
:::

‎CLAUDE.md‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ Educational course repository for "Python package development" by DHI. Course co
1616

1717
## Repository Structure
1818

19+
- `standards.md` — The course distilled into linkable rules; published at `standards.html` and used as the rubric by the `review-python-package` skill. Keep the two in sync.
20+
- `.claude/skills/review-python-package/` — Skill that audits a Python package against `standards.md`
1921
- `*.qmd` files — Course modules (00-07), each a Quarto slide deck
2022
- `_quarto.yml` — Quarto site configuration
2123
- `projects/data_cleaning/` — Capstone homework project (progressive weekly assignments)

‎README.md‎

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,34 @@
33
This repo contains slides used in the course "Python package development".
44
The course is run periodically and the material is kept up to date with current Python tooling.
55

6+
## Python package standards
7+
8+
The whole course distilled into one page of rules — every rule has its own link, so you can
9+
point someone at exactly the thing you mean.
10+
11+
**<https://dhi.github.io/python-package-development/standards.html>**
12+
13+
```
14+
…/standards.html#mutable-default-arguments
15+
…/standards.html#composition-over-inheritance
16+
…/standards.html#libraries-loose-applications-pinned
17+
```
18+
19+
Source: [`standards.md`](standards.md).
20+
21+
### Reviewing a package against the standards
22+
23+
[`.claude/skills/review-python-package/`](.claude/skills/review-python-package/) is a
24+
[Claude Code](https://claude.com/claude-code) skill that audits a package repository against
25+
these standards — layout, `pyproject.toml`, dependencies, tests, code smells, docs, CI and
26+
release setup — and reports findings linked to the rule each one breaks.
27+
28+
Copy the folder into `~/.claude/skills/` (or your project's `.claude/skills/`), then:
29+
30+
```
31+
> review this package against the DHI standards
32+
```
33+
634
## Course description
735

836
Python is the language of choice for data science, scientific computing and AI.
@@ -48,6 +76,8 @@ CI/CD via GitHub Actions (`.github/workflows/publish.yml`) renders and publishes
4876

4977
## Repository Structure
5078

79+
- `standards.md` — The course distilled into linkable rules (published as `standards.html`)
80+
- `.claude/skills/review-python-package/` — Claude Code skill that audits a package against `standards.md`
5181
- `*.qmd` — Course modules (00-07), each a Quarto reveal.js slide deck
5282
- `_quarto.yml` — Quarto site configuration
5383
- `projects/data_cleaning/` — Capstone homework project (progressive weekly assignments)

‎index.qmd‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
title: "Python package development"
33
---
44

5+
[**Python package standards**](standards.md) — the rules from the course, on one page.
6+
57
[Introduction](00_introduction.qmd)
68

79
## Learning modules

‎projects/data_cleaning/04_Project_module.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ In this module, we will use some files from the python library template. When yo
88

99
- Create new branch `action-formatting` (Make sure changes from last module have been merged, and that you start from the main branch)
1010
- 4.1 Github Action
11-
- Copy the `Makefile` from the python template <https://github.com/DHI/template-python-library> to your own library. It can sit in the root of your repo (make sure it is part of your github repo dir however)
11+
- Copy the `justfile` from the python template <https://github.com/DHI/template-python-library> to your own library (install `just` with `uv tool install rust-just`). It can sit in the root of your repo (make sure it is part of your github repo dir however)
1212
- Copy the GitHub action file `full_test.yml` (in the `.github/workflows` folder) from the python template <https://github.com/DHI/template-python-library> to your own library. Make sure it sits in the same folder (`.github/workflows`).
1313
- Change all occurrences of "my_library" in the yml file to your package name "tscleaner"
1414
- Comment out the line with `ruff-action` with "#"

0 commit comments

Comments
 (0)