1 Counting
Build it yourself. Read the tutorial is the other way to read this part.
If you start at this part, make your clone as Get the project says, and then run this command. It puts in your clone the files that this part starts from. A file that the project deleted before this part stays, so delete it if git check lists it:
git rm -rq --cached --ignore-unmatch -- :/ && git restore --source 6a63758166d3 --staged --worktree -- :/just setuptally must count the words of a text. First we write a function that counts, and try it alone. Then the command reads a text, and prints what the function counts.
The code before this part. The code after it.
1.1 A function that counts
A word counter needs a way to count. A function, count, takes a text and gives a dictionary from each word to how
many times it appears. It goes in src/tally/__init__.py, above main. The command does not use it yet.
Apply the patch to src/tally/__init__.py, from the top of the project:
curl -fsSL https://github.com/rahuldave/tally/commit/12fcbe75226dde15e7500b71439bad84712fd2b0.diff | git apply --include=src/tally/__init__.pyThe patch puts count above the line def main() -> None:, with two blank lines between them.
uv run python -c "from tally import count; print(count('a b a'))"It prints {'a': 2, 'b': 1}, two of a and one of b. So the function works, though the command still has
nothing to count.
Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:
git check 12fcbe75226dIf you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:
git restore --source 6a63758166d3 --staged -- :/ && git restore --source 12fcbe75226d --staged --worktree -- :/What changed
src/tally/__init__.py: a dictionary from each word to how many times it appears. 7 lines added. The file.- look at
counts[word] = counts.get(word, 0) + 1
- look at
The patch to src/tally/__init__.py
@@ -1,5 +1,12 @@
"""tally: count the words in a text."""
+def count(text):
+ counts = {}
+ for word in text.split():
+ counts[word] = counts.get(word, 0) + 1
+ return counts
+
+
def main() -> None:
print("tally: nothing to count yet")1.2 The command counts
count works, but the command still prints that it has nothing to count. main must read a text and print the
counts. It reads the file that the command names, or the standard input when the command names no file. The module
sys gives both the arguments of the command and the standard input.
Apply the patch to src/tally/__init__.py, from the top of the project:
curl -fsSL https://github.com/rahuldave/tally/commit/eb951f74756383392f528427a0cf44e135d5c64f.diff | git apply --include=src/tally/__init__.pyThe patch adds import sys under the docstring of the module, and writes main again, in place of the old one.
echo "a b a" | uv run tallyIt prints 2 a and then 1 b. The command now counts.
Check your files against this move. The command prints nothing when they match, and otherwise shows what differs:
git check eb951f747563If you are stuck, this command puts the files of this move in place of yours. A file that you made yourself stays:
git restore --source 12fcbe75226d --staged -- :/ && git restore --source eb951f747563 --staged --worktree -- :/What changed
src/tally/__init__.py:mainreads the text and prints the counts. 5 lines added, 1 removed. The file.- look at
for word, n in sorted(count(text).items()):
- look at
The patch to src/tally/__init__.py
@@ -1,5 +1,7 @@
"""tally: count the words in a text."""
+import sys
+
def count(text):
counts = {}
@@ -9,4 +11,6 @@ def count(text):
def main() -> None:
- print("tally: nothing to count yet")
+ 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)