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 soltantoA
eB
.
Il file di sopra - input_01.csv
- rispetto a questo schema ha diversi problemi:
- riga
3
, colonna1
, il campo obbligatoriotext
non è 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: true
impone 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.