Commit 863b37be authored by Pierre Dittgen's avatar Pierre Dittgen
Browse files


parent ee73c669
# Migration notes
## TableSchema
### descriptor
fields = shema.descriptor.get('fields')
fields = schema.get('fields')
## Tabulator
### Tabulator stream
import tabulator
def consume_source(source, **options)
stream =, **options)
# Get source headers
headers = next(stream.iter())
# And source body rows
body_rows = list(stream.iter())
return headers, body_rows
from frictionless import Table
def consume_source(source, **options)
stream = Table(source, **options)
# Get source headers
headers = stream.header
# And source body rows
body_rows = list(stream.data_stream)
return headers, body_rows
### Tabulator loader
- `tabulator.loader.Loader` base class is replaced by `frictionless.Loader`
- methods to implement have changed
## Goodtables
### Custom checks
- `goodtables.registry.check` is no more used to decorate a custom check class
- custom check classes have to subclass `frictionless.Check` base class
- methods to implement have changed
### frictionless.Plugin
The new way to add custom checks, controls, dialects, loaders, parsers, servers
### Error
- `goodtables.Error` class is replaced by `frictionless.errors.Error` base class
- all the other errors are subclasses, either of `frictionless.errors.Error` directly
or other errors like `frictionless.errors.SourceError` or `frictionless.errors.HeaderError`
- Each error class defines 5 properties: `code`, `name`, `tags`, `template` and `description`, e.g.:
class ExtraHeaderError(HeaderError):
code = "extra-header"
name = "Extra Header"
tags = ["#head", "#structure"]
template = 'There is an extra header "{cell}" in field at position "{fieldPosition}"'
description = "The first row of the data source contains header that does not exist in the schema."
- Error constructor takes 5 named parameters: `note`, `cell`, `cells`, `field_name` and `field_position`
- compared to `goodtables` version, the new error system is **much less flexible**:
- error message templates are hard-coded within error classes
- template variables are restricted to 6 pre-defined values:
- passed as constructor parameter: `cell` (cell value), `fieldName`, `fieldPosition`, `fieldNumber`, `note` (free text)
- or provided by the engine: `rowPosition`
### Inspector
- `Inspector.inspect` function is replaced by `frictionless.validate_table`
- `order_fields` option is replaced by `sync_schema`
- `error_limit` option is replaced by `limit_errors`
- `checks` option is replaced by `pick/skip_errors` and `extra_checks`
import logging
from pathlib import Path
import pytest
import frictionless.errors as errors
from frictionless import validate_table, Schema, Table
from frictionless.exceptions import FrictionlessException
script_dir = Path(__file__).resolve().parent
log = logging.Logger(__name__)
def simple_contact_schema_path():
......@@ -43,7 +47,7 @@ def test_validate_csv(simple_contact_schema_path, simple_contact_csv_path):
def test_tabulator_stream(simple_contact_csv_path):
# Below code replace
# Below code replaces
# stream =, **options)
# headers = next(stream.iter())
......@@ -56,3 +60,15 @@ def test_tabulator_stream(simple_contact_csv_path):
assert len(body_rows) == 2
for row in body_rows:
assert len(row) == len(headers)
def test_error_class():
# err = Error(code="extra-header", message_substitutions={"column-name": "foo"})
err = errors.ExtraHeaderError(
note="This is a note",
cell="cell content",
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment