Conversion¶
orm_loader.conversion interprets raw values for every file load, whatever the file format.
ConversionPolicy¶
ConversionPolicy is a frozen settings object passed to load_file(policy=...). It holds the settings shared by every column and one handler for each kind of column type.
| Field | Meaning |
|---|---|
nulls |
NullPolicy: what counts as a missing value |
errors |
ErrorPolicy: what happens to unreadable and missing required values |
text, integer, floating, numeric, boolean, date, datetime |
The handler for that kind of column, each with its own settings |
handlers |
Handlers for further column types, or replacements, by SQLAlchemy type class |
columns |
Handlers for single columns by (table_name, column_name) |
policy = ConversionPolicy(
nulls=NullPolicy(text_markers=frozenset({"NULL"})),
errors=ErrorPolicy(on_error="reject_row", max_rejects=0.01),
date=DateHandler(formats=("dd/mm/yyyy",)),
columns={("concept", "concept_code"): TextHandler(strip=False)},
)
The settings of one load, shared by every column.
The handler for a column is, in order, the entry in columns and the
handler for the most specific class of the column type (the stored type
of a TypeDecorator) among handlers and the built-in fields. A
column type with no handler is an error.
Attributes:
| Name | Type | Description |
|---|---|---|
nulls |
NullPolicy
|
What counts as a missing value. |
errors |
ErrorPolicy
|
What happens to unreadable and missing required values. |
text |
TextHandler
|
Handler for string and text columns. |
enum |
EnumHandler
|
Handler for enumerated columns. |
integer |
IntegerHandler
|
Handler for integer columns. |
floating |
FloatHandler
|
Handler for floating point columns. |
numeric |
NumericHandler
|
Handler for fixed precision columns. |
boolean |
BooleanHandler
|
Handler for boolean columns. |
date |
DateHandler
|
Handler for date columns. |
datetime |
DateTimeHandler
|
Handler for timestamp columns. |
handlers |
Mapping[type, ColumnHandler]
|
Handlers for further column types, or replacements for the built-in ones, by SQLAlchemy type class. |
columns |
Mapping[tuple[str, str], ColumnHandler]
|
Handlers for single columns by |
for_column(sa_type, table_name=None, column_name=None)
¶
Return the handler that interprets a column.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
sa_type
|
TypeEngine[Any]
|
Column type. |
required |
table_name
|
str | None
|
Table the column belongs to. |
None
|
column_name
|
str | None
|
The column. |
None
|
Returns:
| Type | Description |
|---|---|
ColumnHandler
|
The handler for the column. |
Raises:
| Type | Description |
|---|---|
PolicyError
|
No handler matches the column type. Passthrough is chosen
explicitly with |
NullPolicy¶
- Text columns keep every nonempty value verbatim. Only empty and whitespace-only text is null.
- Words such as
NULL,None,N/AandNaNstay as text in text columns. Version 2 turned them into NULL, which dropped concepts with those names. To treat words as missing again, list them intext_markers, for exampleNullPolicy(text_markers=frozenset({"NULL", "None", "N/A", "NaN", "nan", "null", "NA", "n/a"})). Set operations add or remove words from a set you keep. text_markersare exact, case-sensitive words that are null in every text column of the load. Matching ignores surrounding whitespace and applies the same way to every file format. To treat a word as missing in some columns only, subclassTextHandler, overridemissing()and register it inConversionPolicy.columns.empty_is_null=Falsekeeps empty text fields as empty strings. Typed columns still treat empty fields as missing.- Typed columns accept a valid value, a missing word (
null,none,na,n/a,nanand similar) or a real null, and fail otherwise.
What counts as a missing value, shared by every column handler.
Text columns keep every nonempty value verbatim apart from the markers. Typed columns treat empty text and the typed missing words as missing.
Attributes:
| Name | Type | Description |
|---|---|---|
empty_is_null |
bool
|
Empty and whitespace-only text becomes null in text columns. |
text_markers |
frozenset[str]
|
Exact, case-sensitive text values treated as missing in text columns. Matching ignores surrounding whitespace. |
typed_missing_words |
frozenset[str]
|
Lowercase words treated as missing in non-text columns. |
text_missing(trimmed)
¶
Return a mask of trimmed text values that are missing in a text column.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
trimmed
|
Array
|
String array without surrounding whitespace. |
required |
Returns:
| Type | Description |
|---|---|
Array
|
Boolean array that is true where the value is missing. |
typed_missing(trimmed)
¶
Return a mask of trimmed text values that are missing in a typed column.
ErrorPolicy¶
on_error is raise (default) or reject_row. max_rejects stops a reject_row load before the merge. A count stops the load as soon as it is passed, and a fraction is checked once all rows have been read, against the total number of rows read. A load that rejected rows logs a warning with their number and the rejects file.
What happens to a row with an unreadable value or a missing required value.
Attributes:
| Name | Type | Description |
|---|---|---|
on_error |
Literal['raise', 'reject_row']
|
|
max_rejects |
float | None
|
With |
Handlers¶
The handler for a column is the first match of: the entry in ConversionPolicy.columns and the handler for the most specific class of the column type. A TypeDecorator is handled as the type it stores. A column type with no handler is an error that names the table, column and type, raised before any row is processed. Loading such a column unchanged is an explicit choice: columns={("table", "column"): PassthroughHandler()}.
| Handler | Column types | Accepted text | Settings |
|---|---|---|---|
TextHandler |
String, Text |
Any nonempty text; longer than the column is an error | strip |
EnumHandler |
Enum |
One of the labels the column stores | strip |
IntegerHandler |
Integer, SmallInteger, BigInteger |
Optional sign and digits, with an optional all-zero fraction (1.0); a value outside the 16, 32 or 64 bits of the column type is an error |
none |
FloatHandler |
Float |
Decimal or exponent form; Infinity and values that overflow to infinity are errors |
none |
NumericHandler |
Numeric |
Plain and exponent decimal forms such as 1.5, .05 and 1.5E3, converted to an Arrow decimal of the declared precision and scale without rounding; a precision without a scale has scale 0. A value that does not fit the declared digits is an error. The declaration must have a precision of at most 38 digits, see below |
none |
BooleanHandler |
Boolean |
true, t, yes, y, 1, on and their opposites |
true_words, false_words |
DateHandler |
Date |
One of formats, validated against the calendar; year 0 is an error |
formats |
DateTimeHandler |
DateTime |
ISO date and time, or a date in one of formats; see time zones below |
formats |
Dates default to yyyymmdd, dd-mon-yyyy and yyyy-mm-dd. Ambiguous forms such as 02/01/2020 are never guessed; declare DateHandler(formats=("dd/mm/yyyy",)) or ("mm/dd/yyyy",). A timestamp column reads date-only values with its own formats.
Time zones¶
The column type decides, so no value is converted by a convention the schema did not ask for.
- A
DateTime(timezone=True)column requires an offset (Zor+hh:mm) and stores UTC. A value without an offset and a date-only value are errors. - A
DateTimecolumn without a time zone rejects a value with an offset.
Typed input¶
Input that already has a type, such as a Parquet column, is cast to the column type and checked like parsed text. A value that does not come back unchanged when cast back to its input type is an error, so an integer 2 in a Boolean column, a timestamp with a time in a Date column and a decimal that loses digits are all rejected. Float NaN is missing.
In a Numeric column an integer is read exactly and a float is read as its shortest decimal text, so a Parquet float column loads the same values as a CSV of the same numbers. Infinity is an error.
Numeric columns¶
The loader converts only what an Arrow decimal can hold, which is a precision of at most 38 digits. That is also the widest decimal DuckDB stores, and SQLite stores Numeric as a float. A Numeric column with a wider precision or no precision raises a PolicyError before any row is read. To load it anyway, leave the value to the database with columns={("table", "column"): PassthroughHandler()}: the database then parses the text and rounds a value that exceeds the scale, and a value it cannot parse aborts the load.
Adding a column type¶
Subclass ConvertingHandler, implement arrow_type and parse, and pass the handler in ConversionPolicy.handlers for the type class, or in ConversionPolicy.columns for a single column. clean, missing and check can be overridden.
class HexHandler(ConvertingHandler):
def arrow_type(self, sa_type):
return pa.int64()
def parse(self, cleaned, sa_type):
... # return Interpretation(values, invalid)
policy = ConversionPolicy(handlers={MyHexType: HexHandler()})
ConvertingHandler¶
Bases: ColumnHandler
Converts a column in four stages: clean, detect missing, parse, check.
Text input follows the stages. Input that already has a type, such as a
Parquet column, is cast directly with floating NaN read as missing. A
value that does not survive the cast back to its input type is lossy and
unreadable, and check runs on the cast values.
Subclasses supply arrow_type and parse and may override clean,
missing and check.
Attributes:
| Name | Type | Description |
|---|---|---|
distinct |
bool
|
Run the stages once per distinct value and gather the results back, for types whose parse step is expensive per value. |
arrow_type(sa_type)
abstractmethod
¶
Return the Arrow type of the converted values.
check(values, sa_type)
¶
Return a mask of parsed values the column cannot hold, or None when it holds any.
clean(raw, trimmed)
¶
Return the text that is parsed, the trimmed text by default.
missing(trimmed, nulls)
¶
Return a mask of values that count as missing, by the typed rules by default.
parse(cleaned, sa_type)
abstractmethod
¶
Parse cleaned text in which missing values are null.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
cleaned
|
Array
|
String array with missing values set to null. |
required |
sa_type
|
TypeEngine[Any]
|
Column type the values are converted to. |
required |
Returns:
| Type | Description |
|---|---|
Interpretation
|
Parsed values and a mask of values that did not fit. |
ColumnHandler¶
Bases: ABC
Interprets the raw values of the columns of one kind of column type.
A handler is a frozen settings object. It is selected for a column by
ConversionPolicy.for_column and holds no state about the column.
expected(sa_type)
¶
Return the name reported in an error for an unreadable value.
interpret(arr, sa_type, nulls)
abstractmethod
¶
Interpret a raw column without raising on unreadable values.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
arr
|
Array | ChunkedArray
|
Raw column. |
required |
sa_type
|
TypeEngine[Any]
|
Column type the values are converted to. |
required |
nulls
|
NullPolicy
|
What counts as a missing value. |
required |
Returns:
| Type | Description |
|---|---|
Interpretation
|
Converted values with nulls where a value is missing, and a mask that is true where a value was unreadable. |
validate(sa_type)
¶
Raise ValueError when the handler cannot read the column type as declared.