JSON en CSV · oefening
JSON lezen en valideren
Parsen beantwoordt één vraag: “Is deze tekst JSON, en welke Python-waarden beschrijft die?” Valideren beantwoordt een andere: “Voldoen die waarden aan ons catalogusschema?” Succesvol parsen is noodzakelijk, maar niet voldoende.
Dit is geldige JSON:
{"message": "hello"}
Het is geen catalogusdocument. Het heeft de verkeerde velden en geen itemarray.
load leest een bestand; loads leest een string
De s benoemt de stringversies:
json.loads(text) verwerkt een string die al in het geheugen staat. De tegenhanger json.dumps(value) geeft een JSON-string terug. Gebruik voor de projectbestanden het paar dat met handles werkt:
with open(path, encoding="utf-8") as handle:
document = json.load(handle)
load en dump werken elk met één geopend bestandsobject. De namen lijken op elkaar; de invoer vertelt welke erbij hoort.
Valideer containers voordat je erin kijkt
Begin bovenaan en werk naar binnen:
Het exacte type van het document is
dict, met preciesschema_versionenitems.Het exacte type van de versie is
inten de waarde is1.itemsheeft exact het typelist.Elk item heeft exact het type
dicten precies de vijf itemvelden.Elk veld heeft zijn afgesproken type en geldigheidsregel.
Het woord exact doet ertoe bij booleans. In Python is bool een subklasse van int, met een gevolg dat mensen zelden geloven voordat ze het zien:
De eerste regel verklaart waarom een schemacontrole met isinstance zonder bezwaar true accepteert waar een getal werd verwacht. De derde regel staat er alleen om het punt te laten hangen.
Het schema staat true niet toe als hoeveelheid of schemaversie, dus gebruik voor die velden type(value) is int.
Accepteer voor unit_price exact int of float, maar geen bool. Wijs negatieve waarden af en wijs met math.isfinite niet-eindige floats af.
Houd niet-standaardgetallen buiten
De JSON-parser van Python accepteert standaard NaN en Infinity om compatibiliteitsredenen, hoewel het geen getallen uit de JSON-standaard zijn. Geef een functie voor parse_constant mee die ValueError opwerpt:
def reject_constant(value):
raise ValueError(f"invalid JSON number: {value}")
json.load(handle, parse_constant=reject_constant)
Nu jij
Implementeer validate_document(document) en read_catalog_json(path). Werk write_catalog_json bij zodat die het document valideert vóór het schrijven. Hetzelfde schema bewaakt zo beide richtingen.
Geef het gevalideerde document terug uit zowel het valideren als het lezen. Laat json.JSONDecodeError en je ValueError-meldingen zichtbaar blijven; les 6 bepaalt waar de opdracht voor de gebruiker ze opvangt.
json.load is geslaagd. Wat is daarmee aangetoond?
Waarom gebruikt het schema type(value) is int voor quantity?
Opdracht
Implementeer validate_document(document) en read_catalog_json(path), en roep de validatie vervolgens vanuit write_catalog_json aan vóór het openen van het uitvoerbestand.
Wijs onjuist gevormde JSON, niet-standaard NaN/Infinity, verkeerde of extra velden, verkeerde containers, lege tekst of tekst met witruimte eromheen, negatieve of niet-eindige getallen en booleans in integer- of getalvelden af. Geef het geldige document ongewijzigd terug.