Validating data with the CLIยถ

This page is a copy-paste tour of the pandera command-line interface using pandas, CSV data, and a YAML schema (the cli extra pulls in PyYAML). Run the commands in order in a terminal.

Install Pandera with the CLI and strategies extrasยถ

Install pandas, the CLI (Typer and Rich), and Hypothesis (needed for pandera generate later in this guide):

pip install 'pandera[pandas,cli,strategies]'

Create a sample datasetยถ

Write a small CSV to /tmp/dataset.csv:

cat <<'EOF' > /tmp/dataset.csv
id,name
1,alice
2,bob
3,carol
EOF

Infer a schema from the dataยถ

Write an inferred schema to /tmp/schema.yaml:

pandera infer -d /tmp/dataset.csv -o /tmp/schema.yaml

You can view the yaml schema with

cat /tmp/schema.yaml
schema_type: dataframe
api: pandas
columns:
  id:
    dtype: int64
    greater_than_or_equal_to: 1.0
    less_than_or_equal_to: 3.0
  name:
    dtype: object
    str_length:
      min_value: 3
      max_value: 5
      exact_value: null
index:
- dtype: int64
coerce: true

You should see a short summary (paths, shape, columns) and a line that the schema was written successfully.

Validate the good dataยถ

pandera validate -s /tmp/schema.yaml -d /tmp/dataset.csv
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Validation succeeded โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚   Backend    pandas                                                          โ”‚
โ”‚                                    Checks                                    โ”‚
โ”‚ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”‚
โ”‚ โ”ƒ Level   โ”ƒ Target    โ”ƒ Requirement                              โ”ƒ Status  โ”ƒ โ”‚
โ”‚ โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ โ”‚
โ”‚ โ”‚ data    โ”‚ index     โ”‚ dtype: int64                             โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ index     โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ column present                           โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ dtype: int64                             โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ check: greater_than_or_equal_to          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ check: less_than_or_equal_to             โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ column present                           โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ dtype: object                            โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ check: str_length                        โ”‚ passed  โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ All listed schema- and data-level requirements passed. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

You should see a Validation succeeded report (Rich tables if Rich is installed) and exit code 0.

Create data that fails validationยถ

The inferred schema expects id to be numeric and name to be text. The following file puts a non-numeric value in id:

cat <<'EOF' > /tmp/invalid_dataset.csv
id,name
x,bob
2,carol
EOF

Validate the invalid dataยถ

pandera validate -s /tmp/schema.yaml -d /tmp/invalid_dataset.csv
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Validation failed โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚   Backend    pandas                                                          โ”‚
โ”‚                                Check results                                 โ”‚
โ”‚ โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”‚
โ”‚ โ”ƒ Level   โ”ƒ Target    โ”ƒ Requirement                              โ”ƒ Status  โ”ƒ โ”‚
โ”‚ โ”กโ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ โ”‚
โ”‚ โ”‚ data    โ”‚ index     โ”‚ dtype: int64                             โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ index     โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ column present                           โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ dtype: int64                             โ”‚ failed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ check: greater_than_or_equal_to          โ”‚ failed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ id        โ”‚ check: less_than_or_equal_to             โ”‚ failed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ column present                           โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ dtype: object                            โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ non-null values                          โ”‚ passed  โ”‚ โ”‚
โ”‚ โ”‚ data    โ”‚ name      โ”‚ check: str_length                        โ”‚ passed  โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚                               Failure details                                โ”‚
โ”‚ โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ณโ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”“ โ”‚
โ”‚ โ”ƒ Level โ”ƒ Target โ”ƒ Reason           โ”ƒ Failure cases    โ”ƒ Message           โ”ƒ โ”‚
โ”‚ โ”กโ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ•‡โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”โ”ฉ โ”‚
โ”‚ โ”‚ data  โ”‚ โ€”      โ”‚ dtype_coercion_โ€ฆ โ”‚ index            โ”‚ Error while       โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ failure_case 0 0 โ”‚ coercing 'id' to  โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ x                โ”‚ type int64: Could โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ not coerce <class โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ 'pandas.core.seri โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ es.Series'>       โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ data_โ€ฆ            โ”‚ โ”‚
โ”‚ โ”‚ data  โ”‚ id     โ”‚ wrong_dtype      โ”‚ index            โ”‚ expected series   โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ failure_case 0 0 โ”‚ 'id' to have type โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ x                โ”‚ int64, got object โ”‚ โ”‚
โ”‚ โ”‚ data  โ”‚ id     โ”‚ check_error      โ”‚ TypeError("'>='  โ”‚ Error while       โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ not supported    โ”‚ executing check   โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ between          โ”‚ function:         โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ instances of     โ”‚ TypeError("'>='   โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ 'str' and        โ”‚ not supported     โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ 'float'")        โ”‚ between instances โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ of 'str' and โ€ฆ    โ”‚ โ”‚
โ”‚ โ”‚ data  โ”‚ id     โ”‚ check_error      โ”‚ TypeError("'<='  โ”‚ Error while       โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ not supported    โ”‚ executing check   โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ between          โ”‚ function:         โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ instances of     โ”‚ TypeError("'<='   โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ 'str' and        โ”‚ not supported     โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚ 'float'")        โ”‚ between instances โ”‚ โ”‚
โ”‚ โ”‚       โ”‚        โ”‚                  โ”‚                  โ”‚ of 'str' and โ€ฆ    โ”‚ โ”‚
โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ดโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

This should exit with a non-zero status. You should see Validation failed on standard error plus tables listing which checks passed or failed and failure details (exact layout depends on your Pandera and Rich versions).

Generate synthetic data from the schemaยถ

pandera generate uses hypothesis to draw data that satisfies the schema โ€” useful for exercising downstream code without shipping real data:

pandera generate -s /tmp/schema.yaml -o /tmp/sample.csv --size 5
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Generate โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚   Schema file       schema.yaml   โ”‚
โ”‚   Schema kind       pandas        โ”‚
โ”‚   Schema            2 column(s)   โ”‚
โ”‚   Requested size    5             โ”‚
โ”‚   Output            sample.csv    โ”‚
โ”‚   Writer            csv           โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚ Generated             โ”‚
โ”‚ DataFrame shape 5 ร— 2 โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ
Wrote generated data to sample.csv

The values satisfy the schema but are not realistic โ€” the name column, for example, holds arbitrary strings of the inferred length. See Data synthesis strategies for what this does and does not give you.

generate currently supports pandas dataframe schemas and xarray data_array / dataset schemas. xarray schemas can also be written to NetCDF:

pandera generate -s /tmp/ds_schema.yaml -o /tmp/data.nc --size 5

The api fieldยถ

Every serialized schema carries an optional top-level api field declaring the underlying dataframe API of the data to validate: pandas, modin, dask, pyspark.pandas, polars, ibis, or pyspark.sql. The CLI reads it to pick the data loader and the default validation backend, and it defaults to pandas when the field is absent, so schema files written before the field existed keep working:

schema_type: dataframe
api: pandas
columns:
  id:
    dtype: int64

Validate through the Narwhals backendยถ

Pandas, Polars, Ibis, and PySpark SQL schemas can validate through the Narwhals-powered backend by passing --backend narwhals to pandera validate. Install the narwhals extra alongside the dataframe library you use:

pip install 'pandera[cli,narwhals,pandas]'

Then pass the option when validating a pandas, Polars, Ibis, or PySpark SQL schema. With the pandas schema and dataset from the steps above:

pandera validate -s /tmp/schema.yaml -d /tmp/dataset.csv --backend narwhals

The report names the validation backend that actually ran, so you can see the Narwhals backend in effect (Backend: narwhals instead of Backend: pandas):

โ•ญโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ Validation succeeded โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฎ
โ”‚   Backend    narwhals                                                        โ”‚
โ”‚                                    Checks                                    โ”‚
โ”‚ ...                                                                          โ”‚
โ•ฐโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ All listed schema- and data-level requirements passed. โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ•ฏ

This is equivalent to running the CLI with the PANDERA_USE_NARWHALS_BACKEND=True environment variable set:

PANDERA_USE_NARWHALS_BACKEND=True pandera validate -s /tmp/schema.yaml -d /tmp/dataset.csv

The data is loaded per the schemaโ€™s api field above, which must be pandas, polars, ibis, or pyspark.sql. The Narwhals backend swaps pd.DataFrame dispatch only, so the other pandas-like APIs (modin, dask, pyspark.pandas) stay on their native backends and passing --backend narwhals for them exits with an error.

Important

Other backends and formats

The same CLI supports Polars, PySpark, Ibis, and other loaders depending on how you install Pandera and which --backend you pass to infer / validate. Schema files can be YAML (install pandera[io] for PyYAML) or JSON; infer can also emit Python modules. Data files can be Parquet, Feather, JSON, and more for pandas-like backends.

For command options and limitations, see the CLI reference.