0 Where the hooks start

Build it yourself. Read the tutorial is the other way to read this part.

just setup

tally counts the words of a text. Nothing checks the code before a git commit, so a file with a syntax error can go into git. The recipes of the justfile show what the project can do now.

just --list

It lists the recipes of tally, and none of them checks the code.

Check your files against this part. The command prints nothing when they match, and otherwise shows what differs:

git check eb951f747563

If you are stuck, this command puts the files of this part in place of yours. A file that you made yourself stays:

git rm -rq --cached --ignore-unmatch -- :/ && git restore --source eb951f747563 --staged --worktree -- :/

What changed

  • .gitignore: New, 10 lines. The file.
  • .python-version: New, 1 line. The file.
  • README.md: New, 3 lines. The file.
  • justfile: adds recipe default, recipe run, recipe setup, recipe test. New, 15 lines. The file.
  • pyproject.toml: New, 14 lines. The file.
  • src/tally/__init__.py: adds count, main. New, 16 lines. The file.
  • src/tally/__main__.py: New, 3 lines. The file.
  • uv.lock: New, 8 lines. The file.
The diff of .gitignore
@@ -0,0 +1,10 @@
+# Python-generated files
+__pycache__/
+*.py[oc]
+build/
+dist/
+wheels/
+*.egg-info
+
+# Virtual environments
+.venv
The diff of .python-version
@@ -0,0 +1 @@
+3.12
The diff of README.md
@@ -0,0 +1,3 @@
+# tally
+
+Count the words in a text.
The diff of justfile
@@ -0,0 +1,15 @@
+# The recipes of tally. Each one runs through uv, in the project's own environment.
+default:
+    @just --list
+
+# Make the environment of this step: the first command of every step
+setup:
+    uv sync
+
+# Count the words of a file
+run file:
+    uv run tally {{ file }}
+
+# Run the tests
+test:
+    uv run python -m unittest discover -s tests -q
The diff of pyproject.toml
@@ -0,0 +1,14 @@
+[project]
+name = "tally"
+version = "0.1.0"
+description = "Count the words in a text"
+readme = "README.md"
+requires-python = ">=3.12"
+dependencies = []
+
+[project.scripts]
+tally = "tally:main"
+
+[build-system]
+requires = ["uv_build>=0.12.13,<0.13.0"]
+build-backend = "uv_build"
The diff of src/tally/__init__.py
@@ -0,0 +1,16 @@
+"""tally: count the words in a text."""
+
+import sys
+
+
+def count(text):
+    counts = {}
+    for word in text.split():
+        counts[word] = counts.get(word, 0) + 1
+    return counts
+
+
+def main() -> None:
+    text = open(sys.argv[1]).read() if len(sys.argv) > 1 else sys.stdin.read()
+    for word, n in sorted(count(text).items()):
+        print(n, word)
The diff of src/tally/__main__.py
@@ -0,0 +1,3 @@
+from tally import main
+
+main()

The code.