Migration Context¶
iceberg_ops.migration¶
BaseMigration and MigrationContext — the two objects every
migration file works with.
Conventions¶
version— zero-padded 4-digit string matching the file’sNNNNprefix.upgrade()— must be idempotent.downgrade()— exact reverse ofupgrade; raiseNotImplementedErrorwhen a full undo is impossible (e.g. column removal requires a table rewrite).
- class iceberg_ops.migration.MigrationContext(catalog, namespace, version, description)[source]¶
Bases:
objectRuntime environment injected into every
upgrade()/downgrade()call.- Variables:
catalog (Catalog) – The live PyIceberg catalog being managed.
namespace (str) – The target namespace this migration operates on (e.g.
"sales","finance"). Usectx.qualified(name)to build fully-qualified table identifiers.version (str) – Version string of the migration currently executing.
description (str) – Human-readable description of the migration.
- Parameters:
- qualified(table_name)[source]¶
Return a fully-qualified table identifier.
If table_name already contains a dot (
"sales.orders"), it is returned unchanged. Otherwise<namespace>.<table_name>is built.- Parameters:
table_name (
str) – Bare ("orders") or qualified ("sales.orders") table name.- Returns:
The fully-qualified identifier.
- Return type:
Example
# ctx.namespace = "sales" ctx.qualified("orders") # -> "sales.orders" ctx.qualified("sales.orders") # -> "sales.orders" (unchanged)
- create_table_if_not_exists(identifier, schema, *, partition_spec=None, sort_order=None, properties=None, location=None)[source]¶
Create an Iceberg table or silently return the existing one.
The parent namespace (everything before the last dot, so nested namespaces such as
"sales.eu"work) is created automatically if it does not exist. If another process creates the table between the existence check and the create, the existing table is returned.- Parameters:
identifier (
str) – Table name — relative ("orders") or qualified ("sales.orders"). Relative names are qualified withctx.namespace.schema (
Schema|Schema) – Schema used when creating a new table.partition_spec (
PartitionSpec|None, default:None) – Partition spec for a new table. Default: unpartitioned. Its fields reference source field ids, so it needs apyiceberg.schema.Schema; with apa.Schema, create the table first and then callupdate_partition_spec().sort_order (
SortOrder|None, default:None) – Sort order for a new table. Default: unsorted. Like partition_spec, it needs apyiceberg.schema.Schema; with apa.Schema, callreplace_sort_order()after creating the table.properties (
dict[str,str] |None, default:None) – Table properties for a new table.location (
str|None, default:None) – Table location for a new table. Default: chosen by the catalog.
- Returns:
The created table, or the existing one unchanged. The keyword arguments apply only when the table is created; an existing table is never altered to match them.
- Return type:
- Raises:
ValueError – If schema is a
pa.Schemaand partition_spec or sort_order has fields. Raised before anything (namespace or table) is created.
- get_helper(identifier)[source]¶
Return a
SchemaEvolutionHelperbound to identifier.Power-user escape hatch — the most common operations (add, enforce, rename, delete columns) are exposed directly on this context. Reach for the helper when you need its lower-level primitives or the
contract=kwarg.- Parameters:
identifier (
str) – Table name — relative or qualified.- Returns:
A helper bound to the freshly loaded table.
- Return type:
- Raises:
NoSuchTableError – If the table does not exist.
- add_column(identifier, name, field_type, *, doc=None)[source]¶
Add a column to a table.
Non-idempotent — raises if the column already exists. Use
enforce_column()for the idempotent variant.Supports dotted paths for nested struct fields (e.g.
"address.zip_code"); the parent struct must already exist.- Parameters:
identifier (
str) – Table name — relative or qualified.name (
str) – New column name. Dotted paths target nested struct fields.field_type (
IcebergType|DataType) – The column’s type. A primitive PyArrow type (e.g.pa.string()) is translated to its Iceberg equivalent.doc (
str|None, default:None) – Description stored in the Iceberg schema catalog.
- Raises:
NoSuchTableError – If the table does not exist.
ValueError – If the column already exists, the parent struct of a dotted name does not exist, or a PyArrow field_type has no Iceberg primitive equivalent.
- Return type:
- enforce_column(identifier, name, field_type, *, doc=None, contract=None, legacy_archival=False)[source]¶
Idempotent column enforcement (delegates to
SchemaEvolutionHelper.enforce_column()).A column that already has an equivalent type (including an identical struct, list or map) is left alone, apart from a doc update. A promotion the Iceberg spec allows (
inttolong,floattodouble, wider decimal precision at the same scale) is applied in place; any other change, including ones PyIceberg itself would accept such asstringtobinary, is incompatible. Withlegacy_archival=False(default), an incompatible type change raisespyiceberg.exceptions.ValidationErrorand leaves the table untouched. Withlegacy_archival=True, the existing column is renamed to<name>__legacy_Nand a fresh column is added; a step 2 failure reverses step 1 (compensating transaction). Archival happens only on a genuine type incompatibility, never because of a commit error or a failing contract.- Parameters:
identifier (
str) – Table name — relative or qualified.name (
str) – Canonical column name. Dotted paths target nested struct fields.field_type (
IcebergType|DataType) – Intended type. A primitive PyArrow type (e.g.pa.float64()) is translated to its Iceberg equivalent.doc (
str|None, default:None) – Description stored in the Iceberg schema catalog.contract (
SchemaContract|None, default:None) – If provided, enforced once after the operation completes.legacy_archival (
bool, default:False) – Opt-in to the archive-and-recreate flow on incompatible type. DefaultFalse.
- Raises:
pyiceberg.exceptions.ValidationError – If the type is incompatible and
legacy_archivalisFalse.ValueError – If archival is requested for a column referenced by the partition spec, sort order or identifier fields.
SchemaContractViolation – If contract is given and the table does not conform.
- Return type:
- enforce_rename(identifier, old_name, new_name, *, doc=None, contract=None)[source]¶
Idempotent rename (delegates to
SchemaEvolutionHelper.enforce_rename()).Behaviour depends on which of old_name / new_name exists in the current schema; see the helper docstring for the matrix. Supports dotted paths for nested struct fields. When both exist, the blocking new_name is archived to
<new_name>__legacy_N(made optional,[ARCHIVED]doc) unless the partition spec, sort order or identifier fields reference it, in which caseValueErroris raised and the table is left untouched.- Parameters:
identifier (
str) – Table name — relative or qualified.old_name (
str) – Current column name. Dotted paths target nested struct fields.new_name (
str) – Desired column name; must share old_name’s parent struct.doc (
str|None, default:None) – Description to set on the renamed column.contract (
SchemaContract|None, default:None) – If provided, enforced once after the operation completes (also when the rename is a no-op).
- Raises:
NoSuchTableError – If the table does not exist.
ValueError – If the names do not share a parent struct, the parent struct does not exist, or a colliding new_name is referenced by the partition spec, sort order or identifier fields.
SchemaContractViolation – If contract is given and the table does not conform.
- Return type:
- delete_column(identifier, column_name)[source]¶
Delete a column from the table schema (metadata-only).
Old data files still contain the column but it becomes invisible to queries after this operation.
- Parameters:
- Raises:
NoSuchTableError – If the table does not exist.
ValueError – If the column does not exist.
- Return type:
- update_partition_spec(identifier, add_fields=None, remove_fields=None)[source]¶
Evolve the partition spec of a table.
Uses PyIceberg’s
table.update_spec()context manager to add or remove partition fields in a single atomic commit.- Parameters:
identifier (
str) – Table name — relative or qualified.add_fields (
list[tuple[str,Any,str]] |None, default:None) –Each tuple contains:
column_name— source column in the table schema.transform— a PyIcebergTransforminstance (e.g.DayTransform(),IdentityTransform()).partition_name— the name for the new partition field.
remove_fields (
list[str] |None, default:None) – Names of partition fields to remove (void-out).
- Return type:
Example
from pyiceberg.transforms import DayTransform ctx.update_partition_spec("orders", add_fields=[ ("created_at", DayTransform(), "created_day"), ])
- replace_sort_order(identifier, sort_fields=None)[source]¶
Replace the sort order of a table.
Builds a new sort order from the provided column / direction pairs and commits it via
table.update_sort_order().- Parameters:
- Raises:
ValueError – If direction is not
"asc"or"desc".- Return type:
Example
ctx.replace_sort_order("orders", sort_fields=[ ("order_id", "asc"), ("created_at", "desc"), ])
- set_table_properties(identifier, properties)[source]¶
Set one or more Iceberg table properties.
Uses a PyIceberg transaction so all properties land in a single atomic commit.
- Parameters:
- Return type:
Example
ctx.set_table_properties("orders", { "write.parquet.compression-codec": "zstd", })
- unset_table_properties(identifier, keys)[source]¶
Remove one or more Iceberg table properties.
Uses a PyIceberg transaction so all keys are removed atomically. Keys that do not exist are silently ignored.
- Parameters:
- Return type:
Example
ctx.unset_table_properties("orders", [ "write.parquet.compression-codec", ])
- set_compaction_target_size(identifier, target_mb)[source]¶
Set the target data file size for writers.
Sets the standard Iceberg
write.target-file-size-bytesproperty. PyIceberg’s writers use it as their bin-packing target. iceberg-ops’ compaction helpers take an explicittarget_size_mb(default 512) and do not read it; managed services such as S3 Tables configure compaction targets through their own maintenance settings.- Parameters:
- Return type:
Example
ctx.set_compaction_target_size("orders", target_mb=256)
- set_snapshot_retention(identifier, *, min_snapshots=None, max_age_hours=None)[source]¶
Configure snapshot retention via standard Iceberg properties.
Sets one or both of:
history.expire.min-snapshots-to-keep— minimum number of snapshots Iceberg must retain regardless of age (Iceberg default: 1).history.expire.max-snapshot-age-ms— snapshots older than this become eligible for expiration (Iceberg default: 5 days).
Both conditions must be satisfied for a snapshot to be expired. Calling with both arguments
Noneis a no-op.- Parameters:
- Return type:
Notes
These are the standard Iceberg properties read by engines’ expire-snapshots procedures. Do not set them on AWS S3 Tables: S3 Tables manages retention through its own maintenance configuration, and AWS documents that these properties make its snapshot management fail; a warning is logged when the catalog is configured for S3 Tables.
expire_snapshots()reads these properties when itsmax_age_hours/min_snapshotsarguments are omitted.Example
ctx.set_snapshot_retention("orders", min_snapshots=5, max_age_hours=72)
- set_clustering_keys(identifier, columns, *, direction='asc')[source]¶
Set the table’s Iceberg sort order on columns with a uniform direction.
The sort order is the only portable, spec-defined clustering mechanism; iceberg-ops writes no vendor-specific properties. Whether an engine or managed service uses the sort order when writing or compacting depends on that engine. This is a single
replace_sort_order()commit.- Parameters:
identifier (
str) – Table name — relative or qualified.columns (
list[str]) – One or more column names to cluster by, in priority order. Must be non-empty.direction (
str, default:'asc') –"asc"(default) or"desc". Applied uniformly to every column. For mixed directions, callreplace_sort_order()directly.
- Raises:
ValueError – If columns is empty, or if direction is not
"asc"/"desc".- Return type:
- class iceberg_ops.migration.BaseMigration[source]¶
Bases:
objectAbstract base class for all migration files.
Subclass this and name the subclass
Migrationexactly — the runner discovers it by that name.The runner calls methods in this order:
pre_upgrade() -> upgrade() -> post_upgrade() pre_downgrade() -> downgrade() -> post_downgrade()
All four hook methods (
pre_upgrade,post_upgrade,pre_downgrade,post_downgrade) are optional no-ops by default. Override them to add precondition checks, notifications, or cleanup logic around the core migration.Class attributes¶
- versionstr
Zero-padded 4-digit string (
"0001"). Must be unique within the project.- descriptionstr
Short summary stored in the migration history table.
- upgrade(ctx)[source]¶
Apply this migration. Must be idempotent.
- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Raises:
NotImplementedError – Unless overridden.
- Return type:
- downgrade(ctx)[source]¶
Reverse this migration.
Raise
NotImplementedErrorwhen a full undo is not possible (e.g. column removal requires a full table rewrite in Iceberg).- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Raises:
NotImplementedError – Unless overridden.
- Return type:
- pre_upgrade(ctx)[source]¶
Override to validate preconditions before
upgrade().If this method raises,
upgrade()does not run and the migration is recorded as failed.- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Return type:
- post_upgrade(ctx)[source]¶
Override to perform post-migration actions after
upgrade().If this method raises, the migration is still recorded as applied (the schema change already committed); a warning is logged.
- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Return type:
- pre_downgrade(ctx)[source]¶
Override to validate preconditions before
downgrade().If this method raises,
downgrade()does not run and the rollback fails.- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Return type:
- post_downgrade(ctx)[source]¶
Override to perform post-rollback cleanup.
If this method raises, the rollback is still recorded as completed; a warning is logged.
- Parameters:
ctx (
MigrationContext) – Runtime context: catalog, target namespace and table helpers.- Return type: