Validare dati¶
Il comando validate esegue la validazione di risorse e/o liste di risorse contenute in un datapackage.
In input ad esempio una risorsa tabellare di questo tipo (nella tabella di sotto, i caratteri ··· rappresentano una cella vuota):
| text | number | date | type | |
|---|---|---|---|---|
| Lorem | 37.256 | 2022-01-13 | 012543 | A |
| ··· | ··· | ··· | ··· | ··· |
| Ciao | 2023-01-13 | C |
In formato CSV è:
Questo input ha diversi problemi:
- la colonna numero 4, non ha nome;
- la riga 3 è completamente vuota;
- nella riga 4, manca la colonna 5.
Il comando validate di frictionless è in grado di riconoscerli e restituirli all'utente.
Utilizzando il file input_00.csv come input e lanciando
in output si avrà
# -------
# invalid: input_00.csv
# -------
## Summary
+-----------------------------+-------------------+
| Description | Size/Name/Count |
+=============================+===================+
| File name | input_00.csv |
+-----------------------------+-------------------+
| File size (bytes) | 76 |
+-----------------------------+-------------------+
| Total Time Taken (sec) | 0.028 |
+-----------------------------+-------------------+
| Total Errors | 3 |
+-----------------------------+-------------------+
| Blank Label (blank-label) | 1 |
+-----------------------------+-------------------+
| Blank Row (blank-row) | 1 |
+-----------------------------+-------------------+
| Missing Cell (missing-cell) | 1 |
+-----------------------------+-------------------+
## Errors
+-------+---------+-----------+-------------------------------------------------+
| row | field | code | message |
+=======+=========+===========+=================================================+
| | 4 | blank- | Label in the header in field at position "4" is |
| | | label | blank |
+-------+---------+-----------+-------------------------------------------------+
| 3 | | blank-row | Row at position "3" is completely blank |
+-------+---------+-----------+-------------------------------------------------+
| 4 | 5 | missing- | Row at position "4" has a missing cell in field |
| | | cell | "type" at position "5" |
+-------+---------+-----------+-------------------------------------------------+
La prima parte - Summary - restituisce un riepilogo. Tra le altre cose il nome del file, le sue dimensioni, il numero totale di errori, e il numero di errori per tipo.
La seconda - Errors - restituisce i dettagli di ciascun errore (sopra evidenziati in giallo): numero di riga (la riga di intestazione è la 1) e di colonna in cui è presente l'errore, e la descrizione di dettaglio dello stesso.
È interessante notare come gli errori estratti automaticamente, coincidano con quelli descritti "a mano".
Validare un file JSON
Per validare un file JSON si deve usare l'opzione path:
Output di validazione in formato JSON o YAML¶
È molto importante potere avere l'output di validazione in un formato machine readable, in modo da poter ad esempio fare una validazione giornaliera di uno o più file, archiviare l'esito in un file di log e infine avvisare automaticamente l'utente se il processo non è andato a buon fine.
Per farlo ci sono i flag --json e --yaml. Ad esempio per l'output in JSON, il comando sarà:
Esempio di output in JSON
{
"version": "4.40.5",
"time": 0.032,
"errors": [],
"tasks": [
{
"resource": {
"path": "input_00.csv",
"name": "input_00",
"profile": "tabular-data-resource",
"scheme": "file",
"format": "csv",
"hashing": "md5",
"stats": {
"hash": "cf404937d0c1a8001585d5593640c7c3",
"bytes": 76,
"fields": 5,
"rows": 3
},
"encoding": "utf-8",
"schema": {
"fields": [
{
"type": "string",
"name": "text"
},
{
"type": "string",
"name": "number"
},
{
"type": "date",
"name": "date"
},
{
"type": "string",
"name": "field4"
},
{
"type": "string",
"name": "type"
}
]
}
},
"time": 0.032,
"scope": [
"hash-count-error",
"byte-count-error",
"field-count-error",
"row-count-error",
"blank-header",
"extra-label",
"missing-label",
"blank-label",
"duplicate-label",
"incorrect-label",
"blank-row",
"primary-key-error",
"foreign-key-error",
"extra-cell",
"missing-cell",
"type-error",
"constraint-error",
"unique-error"
],
"partial": false,
"errors": [
{
"label": "",
"fieldName": "field4",
"fieldNumber": 4,
"fieldPosition": 4,
"labels": [
"text",
"number",
"date",
"",
"type"
],
"rowPositions": [
1
],
"code": "blank-label",
"name": "Blank Label",
"tags": [
"#table",
"#header",
"#label"
],
"note": "",
"message": "Label in the header in field at position \"4\" is blank",
"description": "A label in the header row is missing a value. Label should be provided and not be blank."
},
{
"cells": [],
"rowNumber": 2,
"rowPosition": 3,
"code": "blank-row",
"name": "Blank Row",
"tags": [
"#table",
"#row"
],
"note": "",
"message": "Row at position \"3\" is completely blank",
"description": "This row is empty. A row should contain at least one value."
},
{
"cell": "",
"fieldName": "type",
"fieldNumber": 5,
"fieldPosition": 5,
"cells": [
"",
"Ciao",
"2023-01-13",
"C"
],
"rowNumber": 3,
"rowPosition": 4,
"code": "missing-cell",
"name": "Missing Cell",
"tags": [
"#table",
"#row",
"#cell"
],
"note": "",
"message": "Row at position \"4\" has a missing cell in field \"type\" at position \"5\"",
"description": "This row has less values compared to the header row (the first row in the data source). A key concept is that all the rows in tabular data must have the same number of columns."
}
],
"stats": {
"errors": 3
},
"valid": false
}
],
"stats": {
"errors": 3,
"tasks": 1
},
"valid": false
}
Validare un file tabellare a partire da uno schema¶
In input ad esempio questi dati
| text | number | date | code | type |
|---|---|---|---|---|
| Lorem | 37.256 | 2022-01-13 | 012543 | A |
| Ciao | 2023-01-13 | 78956 | C |
che in CSV sono
| input_01.csv | |
|---|---|
A seguire l'elenco dei campi/colonne del file, e i vari vincoli che si vogliono imporre e poter verificare, sul tipo di campo, valori consentiti, obbligatorietà, ecc:
text, un campo stringa, obbligatorionumber, un campo numericodate, un campo di tipo data, con valori che non possono essere successivi al 15 maggio 2022code, un campo stringa, che deve essere composto da 6 caratteri numerici (può iniziare per0, quindi non è un numero)type, un campo stringa, che può avere come valori soltantoAeB.
Il file di sopra - input_01.csv - rispetto a questo schema ha diversi problemi:
- riga
3, colonna1, il campo obbligatoriotextnon è valorizzato; - riga
3, colonna2, c'è una stringa (Ciao) in un campo numerico; - riga
3, colonna3, c'è una data che va oltre il 15 maggio 2022 (2023-01-13); - riga
3, colonna4, c'è una stringa che non è composta da 6 numeri (78956); - riga
3, colonna5, c'è un valore che non è néA, neB, ma èC.
Questo schema si può descrivere in formato YAML, secondo queste specifiche. Il file di descrizione si potrà usare per validare il file e verificare che rispetti lo schema.
Qui sotto il contenuto del file schema_01.yml, per descrivere e validare in formato frictionless lo schema del file di sopra.
path: input_01.csv
name: input_01
profile: tabular-data-resource
scheme: file
format: csv
hashing: md5
encoding: utf-8
schema:
missingValues:
- "NA"
- "NaN"
- "null"
- ""
fields:
- name: text
type: string
title: "label text"
constraints:
required: true # (1)
- name: number
type: number
title: "label number"
- name: date
type: date
title: "label date"
description: "La data di accesso dell'utente nel sistema"
example: '2020-05-15'
constraints:
maximum: '2022-05-15' # (2)
- name: code
type: string
title: "label code"
constraints:
pattern: ^[0-9]{6}$ # (3)
- name: type
type: string
title: "label type"
constraints:
enum: # (4)
- A
- B
- Il vincolo
required: trueimpone che tutte le celle della colonna siano valorizzate - Il valore massimo di data inseribile in questo campo
- L'espressione regolare che i valori delle celle di questo campo devono rispettare
- L'enumerazione, l'elenco, dei valori ammessi per le celle di questo campo
Creare automaticamente un file YAML
Utilizzando il comando describe, puoi creare la struttura di base di un file frictionless che descrive una risorsa, a cui aggiungere poi "a mano" ulteriori proprietà.
Per ogni campo è definito il tipo di campo, con il parametro type, e sono definiti altri vincoli specifici tramite il parametro constraints (documentazione ufficiale). Tra questi ad esempio:
required, per indicare che i valori di quel campo sono obbligatori;maximum, per indicare qual è il valore massimo utilizzabile per un campo (non è applicabile a tutti i tipi di campo)pattern, per indicare, per un campo di tipostring, qual è l'espressione regolare da rispettare;enum, per indicare, per un campo di tipostring, qual è l'elenco dei valori ammissibili.
Utilizzando questo file YAML, che fa riferimento al file CSV di input (path: input_01.csv) è possibile lanciare la validazione:
In output, estratto automaticamente, l'elenco di errori annotato poco sopra.
## Errors
+-------+---------+------------+----------------------------------------------------+
| row | field | code | message |
+=======+=========+============+====================================================+
| 3 | 1 | constraint | The cell "" in row at position "3" and field |
| | | -error | "text" at position "1" does not conform to a |
| | | | constraint: constraint "required" is "True" |
+-------+---------+------------+----------------------------------------------------+
| 3 | 2 | type-error | Type error in the cell "Ciao" in row "3" and field |
| | | | "number" at position "2": type is "number/default" |
+-------+---------+------------+----------------------------------------------------+
| 3 | 3 | constraint | The cell "2023-01-13" in row at position "3" and |
| | | -error | field "date" at position "3" does not conform to a |
| | | | constraint: constraint "maximum" is "2022-05-15" |
+-------+---------+------------+----------------------------------------------------+
| 3 | 4 | constraint | The cell "78956" in row at position "3" and field |
| | | -error | "code" at position "4" does not conform to a |
| | | | constraint: constraint "pattern" is "^[0-9]{6}$" |
+-------+---------+------------+----------------------------------------------------+
| 3 | 5 | constraint | The cell "C" in row at position "3" and field |
| | | -error | "type" at position "5" does not conform to a |
| | | | constraint: constraint "enum" is "['A', 'B']" |
+-------+---------+------------+----------------------------------------------------+
Applicare uno schema definito per un file, ad altri¶
Per farlo basta usare l'opzione --path e lanciare il comando inserendo il percorso del file su cui fare la validazione.
Opzioni del comando¶
Options:
--type TEXT Specify type e.g. "package"
--path TEXT Specify the data path explicitly (e.g. you
need to use it if your data is JSON)
--scheme TEXT Specify scheme [default: inferred]
--format TEXT Specify format [default: inferred]
--hashing TEXT Specify hashing algorithm [default:
inferred]
--encoding TEXT Specify encoding [default: inferred]
--innerpath TEXT Specify in-archive path [default: first]
--compression TEXT Specify compression [default: inferred]
--control TEXT An inline JSON object or a path to a JSON
file that provides the control
(configuration for the data Loader)
--dialect TEXT An inline JSON object or a path to a JSON
file that provides the dialect
(configuration for the parser)
--sheet TEXT The sheet to use from the input data (only
with XLS and ODS files/plugins)
--table TEXT The table to use from the SQL database (SQL
plugin)
--keys TEXT The keys to use as column names for the
Inline or JSON data plugins
--keyed / --no-keyed Whether the input data is keyed for the
Inline or JSON data plugins
--header-rows TEXT Comma-separated row numbers [default:
inferred]
--header-join TEXT Multiline header joiner [default: inferred]
--pick-fields TEXT Comma-separated fields to pick e.g.
"1,name1"
--skip-fields TEXT Comma-separated fields to skip e.g.
"2,name2"
--limit-fields INTEGER Limit fields by this integer e.g. "10"
--offset-fields INTEGER Offset fields by this integer e.g "5"
--pick-rows TEXT Comma-separated rows to pick e.g.
"1,<blank>"
--skip-rows TEXT Comma-separated rows to skip e.g. "2,3,4,5"
--limit-rows INTEGER Limit rows by this integer e.g "100"
--offset-rows INTEGER Offset rows by this integer e.g. "50"
--schema TEXT Specify a path to a schema
--stats-hash TEXT Expected hash based on hashing option
--stats-bytes INTEGER Expected size in bytes
--stats-fields INTEGER Expected amount of fields
--stats-rows INTEGER Expected amount of rows
--buffer-size INTEGER Limit the amount of bytes to be extracted as
a buffer [default: 10000]
--sample-size INTEGER Limit the number of rows to be extracted as
a sample [default: 100]
--field-type TEXT Force all the fields to have this type
--field-names TEXT Comma-separated list of field names
--field-confidence FLOAT Infer confidence. A float from 0 to 1. If 1,
(sampled) data is guaranteed to be valid
against the inferred schema [default: 0.9]
--field-float-numbers / --no-field-float-numbers
Make number floats instead of decimals
[default: False]
--field-missing-values TEXT Comma-separated list of missing values
[default: ""]
--schema-sync / --no-schema-sync
Sync the schema based on the data's header
row
--basepath TEXT Basepath of the resource/package
--pick-errors TEXT Comma-separated errors to pick e.g. "type-
error"
--skip-errors TEXT Comma-separated errors to skip e.g. "blank-
row"
--limit-errors INTEGER Limit errors by this integer
--limit-memory INTEGER Limit memory by this integer in MB
--original / --no-original Don't call infer on resources
--parallel / --no-parallel Enable multiprocessing
--yaml / --no-yaml Return in pure YAML format [default: False]
--json / --no-json Return in JSON format [default: False]
--resource-name TEXT Name of resource to validate
--help Show this message and exit.