Skip to content

Schema Inference

Pass schema=None when the container should infer fields from the records it receives.

Warning

Inferred schemas are convenient for flexible payloads, but explicit schemas are better when downstream systems require a stable contract.

First record

The first non-empty record establishes the initial schema.

from http_to_arrow import ArrowRecordContainer

container = ArrowRecordContainer(schema=None)
container.append({"id": 1, "name": "alpha"})

assert container.schema is not None
assert container.schema.names == ["id", "name"]

An empty first record cannot produce a schema and raises ValueError.

Field growth

When a later record includes a new field, inferred mode widens the schema and backfills earlier rows with nulls.

from http_to_arrow import ArrowRecordContainer

container = ArrowRecordContainer(schema=None, batch_size=1)
container.append({"id": 1})
container.append({"id": 2, "name": "beta"})

assert container.to_table().to_pydict() == {
    "id": [1, 2],
    "name": [None, "beta"],
}

Type widening

Compatible numeric types widen to a common Arrow type. Conflicting shapes that cannot be merged fall back to string.

from http_to_arrow import ArrowRecordContainer

container = ArrowRecordContainer(schema=None)
container.append({"value": 1})
container.append({"value": {"nested": True}})

assert container.to_table().to_pydict() == {
    "value": ["1", "{'nested': True}"],
}

Case-insensitive names

With the default case_insensitive_keys=True, inferred mode preserves the first-seen spelling of a field name and maps later case variants to it.

from http_to_arrow import ArrowRecordContainer

container = ArrowRecordContainer(schema=None)
container.append({"ID": 1})
container.append({"id": 2})

assert container.schema is not None
assert container.schema.names == ["ID"]
assert container.to_table().column("ID").to_pylist() == [1, 2]

Empty materialization

Calling to_table() before an inferred container has a schema or records raises ValueError. Supply an explicit schema if you need an empty table before any records arrive.

Tip

If an empty result is valid in your workflow, initialize the container with an explicit pyarrow.Schema so to_table() can return an empty table with known columns.