Herbruikbare regels en commandoregelinvoer scheiden.
Een echte console-ingang voor een pakket installeren.
Dezelfde CLI via een pakketstartpunt gebruiken met de juiste exitstatus.
Een collega wil je programma vanaf de commandoregel gebruiken, terwijl een andere collega dezelfde berekening in Python wil aanroepen. Maak daarom één bibliotheek met een kleine ingang voor de commandoregel. De twee gebruikers delen de regels, zonder elkaars invoerafhandeling nodig te hebben.
Drie verantwoordelijkheden
De bibliotheekfunctie summary maakt tekst en controleert haar eigen invoer. De CLI leest argumenten, roept die functie aan en schrijft het resultaat. Het startpunt kiest hoe de CLI als proces wordt gestart.
In dit pakket staan die taken in report.py, cli.py en __main__.py. De projectbeschrijving noemt het consolecommando. De meegeleverde __init__.py biedt summary ook als publieke bibliotheekfunctie aan.
Het eerste voorbeeld installeert een ander klein pakket. Daarna starten zowel het geïnstalleerde consolecommando als python -m dezelfde hoofdfunctie. Beide paden zijn echte processen in de projectomgeving.
Een echte installatie biedt dezelfde CLI als consolecommando en als module
from . import main
if __name__ == "__main__":
raise SystemExit(main())
example.py
import subprocess
subprocess.run(["uv", "--quiet", "sync", "--offline"], check=True)
first = subprocess.run([".venv/bin/note-tags", "boek"])
if first.returncode:
raise SystemExit(first.returncode)
second = subprocess.run([".venv/bin/python", "-I", "-m", "note_tags", "kaart"])
raise SystemExit(second.returncode)
Verwachte uitvoer
NIEUW: boek
NIEUW: kaart
Herbruikbare regels eerst
Maak summary bruikbaar zonder console. De functie verwijdert buitenste witruimte van de naam en geeft bijvoorbeeld "3 x fiets" terug. Zij print die tekst niet zelf.
Een lege naam en een ongeldig aantal zijn invoerfouten. In deze opdracht is een aantal precies een int van nul of hoger; een bool telt niet als aantal. Geef daarvoor de gevraagde ValueError, zodat ook een Pythonaanroeper een duidelijke fout krijgt.
Van argumenten naar een bibliotheekaanroep
Je kent argparse uit de eerdere lessen. ArgumentParser beschrijft de invoer: een positionele name en de optionele --count, met type int en standaardwaarde 1. Een opgegeven nul blijft nul en mag niet door de standaardwaarde worden vervangen.
Laat main(argv=None) de argumentlijst ontvangen. Met None leest argparse de echte procesargumenten; met een lijst kun je de functie rechtstreeks uitproberen. Roep daarna de huidige report.summary aan, print het ontvangen resultaat en geef bij succes de integer nul terug.
Een verkeerd geschreven getal wordt al door argparse afgewezen. Geeft summary een ValueError, gebruik dan parser.error(str(error)). Argparse schrijft daarmee naar stderr, de aparte uitvoerstroom voor foutmeldingen, en stopt met status 2.
Onverwachte bibliotheekfouten, zoals RuntimeError, moeten zichtbaar blijven met hun eigen fouttype. Laat ze doorlopen zodat je tijdens het ontwikkelen de oorzaak kunt onderzoeken.
Een installatie een ingang geven
De declaratie onder [project.scripts] koppelt de naam walk-notes aan "walk_notes.cli:main". De functie krijgt hier geen haakjes. Bij installatie maakt uv een startbestand dat deze functie gebruikt.
De meegeleverde controle synchroniseert de omgeving opnieuw vanuit jouw projectbeschrijving. Zij controleert de geïnstalleerde metadata en start het echte consolecommando. Alleen een gelijknamig bronbestand schrijven is dus niet genoeg.
Het pakket ook als module starten
from .cli import main
if __name__ == "__main__":
raise SystemExit(main())
Dit dunne startpunt deelt de CLI in plaats van de parser opnieuw te schrijven. De bewaking voorkomt dat een gewone import van de startmodule meteen argumenten gaat verwerken. SystemExit draagt een teruggegeven status van main over aan het proces.
Veelgemaakte fout: starten tijdens import
Het tweede voorbeeld importeert een startmodule zonder die bewaking. Daardoor probeert argparse meteen een verplicht argument te lezen en stopt het proces. Plaats zulke starthandelingen achter de bewaking en houd de herbruikbare functies apart.
Een onbewaakt startpunt verwerkt per ongeluk argumenten tijdens import
Maak summary(name, count) in src/walk_notes/report.py. Strip de naam en geef f"{count} x {name}" terug. Een lege gestripte naam geeft ValueError("name mag niet leeg zijn"). Een count waarvan type niet precies int is, of die negatief is, geeft ValueError("count moet een niet-negatieve int zijn"). Print niets.
2
Een testbare argparse-hoofdfunctie schrijven
Maak main(argv=None) in src/walk_notes/cli.py. Gebruik argparse met name en --count (int, default 1), parse argv, print de huidige report.summary en geef de integer 0 terug. Importeer report als module binnen het pakket. Verwerk ValueError uit summary met parser.error(str(error)); argparse-invoerfouten geven status 2.
3
Het consolecommando echt installeren
Voeg onder [project.scripts] in pyproject.toml walk-notes = "walk_notes.cli:main" toe. Na echte installatie moet walk-notes fiets --count 3 de regel 3 x fiets schrijven en normaal eindigen. De meegeleverde metadata en overige bronnen hoef je niet te veranderen.
4
Dezelfde CLI als pakketstartpunt aanbieden
Vul src/walk_notes/__main__.py in. Importeer main uit .cli en gebruik onder if __name__ == "__main__": raise SystemExit(main()). python -m walk_notes moet dezelfde CLI uitvoeren. Een gewone import van walk_notes.__main__ mag niets starten; ook een andere teruggegeven main-status moet doorlopen.
Onthoud dit
De bibliotheek geeft waarden of fouten terug; de CLI regelt de console.
Projectmetadata verbindt een commandonaam aan een functie.
Een dun pakketstartpunt bewaart dezelfde CLI en haar exitstatus.
In de volgende module toets je zulke onderdelen gericht met echte tests.