Als de buitenwereld niet meewerkt · oefening
Vang op waar de fout betekenis heeft
Het filter dat de grenswaarde insluit is gerepareerd. Het commando heeft nog één te ruime grens voor foutafhandeling uit hoofdstuk 8:
try:
document = convert_catalog(input_path, output_path, minimum_quantity)
except (FileNotFoundError, UnicodeDecodeError, csv.Error, ValueError) as exc:
...
Die tuple noemt alleen verwachte typen, maar het try-blok omvat lezen, selecteren, valideren en schrijven. De locatie is net zo belangrijk als de klasse. Een ValueError bij het ontleden van een beschadigde CSV-rij is verwachte externe invoer. Een ValueError uit de validatie van de schrijver betekent dat projectcode een ongeldig intern document aan haar eigen schrijver gaf. Beide hetzelfde afhandelen zou dat onderscheid uitwissen.
Begrens één bewerking waarvan je de betekenis begrijpt
Maak run_catalog(input_path, output_path, minimum_quantity). De eerste grens omvat alleen het lezen:
try:
items = read_catalog_csv(input_path)
except (OSError, UnicodeDecodeError, csv.Error, ValueError) as exc:
print(f"Could not read {input_path}: {exc}", file=sys.stderr)
return 1
OSError is de familie van besturingssysteemfouten, waaronder ontbrekende paden, ontbrekende rechten en andere mislukte bestandsbewerkingen. Hier heeft die één betekenis: de gevraagde invoer kon niet worden geopend of gelezen. UnicodeDecodeError, csv.Error en ValueError betekenen dat de bytes, de CSV-syntaxis of het opgegeven schema niet in een catalogus konden worden omgezet.
De melding bevat het exacte invoerpad en de oorzaak binnen die bewerking. stdout blijft leeg. Het belangrijkste is dat de schrijver nog niet is uitgevoerd, zodat een bestaand uitvoerbestand byte voor byte ongewijzigd blijft.
Voer de selectie na die handler uit, buiten elk try-blok:
selected = select_items(items, minimum_quantity)
Als de selectie KeyError, TypeError, ValueError, RuntimeError of zelfs OSError opwerpt, gaat de oorspronkelijke exceptie verder omhoog. Selectie raakt de buitenwereld niet. Een defect daarin een lees- of schrijffout noemen zou dus onjuist zijn.
Geef de uitvoerbewerking een eigen grens
Zet de grens alleen om de schrijver:
try:
document = write_catalog_json(selected, output_path)
except OSError as exc:
print(f"Could not write {output_path}: {exc}", file=sys.stderr)
return 1
Hier is alleen een schrijffout van het besturingssysteem te verwachten. Een ValueError of TypeError uit de validatie schendt een interne invariant en moet ongewijzigd verdergaan.
Druk de succesregel pas af nadat write_catalog_json is teruggekeerd. “Wrote N items” is een bewering over een voltooide bewerking. Die eerder afdrukken zou ten onrechte succes melden.
De werkelijke beperking van het uitvoerbestand
Dit project schrijft rechtstreeks naar het gevraagde pad. Als het besturingssysteem faalt vóór het openen, kan een oud bestand ongewijzigd blijven. Als de fout optreedt na het leegmaken of nadat er al bytes zijn geschreven, kan het bestand ontbreken of onvolledig zijn. Dit hoofdstuk belooft niet dat wijzigingen worden teruggedraaid als dat niet is geïmplementeerd.
Er wordt ook niet automatisch opnieuw geprobeerd. Een ontbrekend pad of een rechtenfout opnieuw proberen zonder iets te veranderen, herhaalt alleen hetzelfde geval. De foutmelding geeft de aanroeper bewijs; ze verzint geen herstelbeleid.
Werk main(argv=None) bij zodat argparse verantwoordelijk blijft voor hulp en grammaticafouten. Geef daarna de drie ontlede waarden door aan run_catalog. Het volledige contract is:
| Situatie | stdout | stderr | status |
|---|---|---|---|
| succes | Wrote N items to PATH. | leeg | 0 |
| lees-/invoerfout | leeg | Could not read INPUT: cause | 1 |
OSError bij uitvoer | leeg | Could not write OUTPUT: cause | 1 |
| parserfout | leeg | gebruiksinstructies en foutmelding van argparse | 2 |
| onverwacht defect | niets beloofd | oorspronkelijke traceback | niet nul |
Implementeer de twee grenzen die elk één bewerking omvatten.
Of het programma niet meer crasht, vertelt niet of je het goed hebt gedaan. Het gaat erom of dezelfde exceptieklasse anders wordt behandeld afhankelijk van waar ze vandaan komt. Een ValueError uit de lezer hoort een korte melding op te leveren; een ValueError uit de eigen validatie van de schrijver hoort nog steeds een traceback te geven. Als één breed try-blok beide omvat, kun jij die twee niet onderscheiden en degene die je programma uitvoert ook niet.
Een ValueError bereikt je code. Waar die vandaan komt bepaalt wat je moet doen. Waarom?
Waarom wordt select_items buiten elk try-blok uitgevoerd?
Opdracht
Refactor de aansturing van de CLI naar run_catalog(input_path, output_path, minimum_quantity).
Vang
OSError,UnicodeDecodeError,csv.ErrorenValueErroralleen rondread_catalog_csvop, druk danCould not read INPUT_PATH: CAUSEaf op stderr en geef1terug.Voer
select_itemsbuiten elktry-blok uit.Vang alleen
OSErrorrondwrite_catalog_jsonop, druk danCould not write OUTPUT_PATH: CAUSEaf op stderr en geef1terug.Druk na geslaagd schrijven
Wrote N items to OUTPUT_PATH.af op stdout en geef0terug.Laat
main(argv=None)argumenten ontleden enrun_catalog(...)teruggeven.
Behoud hulp/status 0 en grammatica/status 2 van argparse. Laat defecten in de selectie en validatiefouten van de schrijver ongewijzigd verdergaan. Voeg geen nieuwe pogingen of beloften over terugdraaien toe.