mafw.db.migration.script

Migration-script representation, naming, rendering and safe writing.

A migration script is a reviewable, editable Python module generated by the service for one supported schema diff. It declares its version identifier, a human-readable summary of the detected change, a content checksum, and the ordered list of playhouse.migrate operations to run inside a migrate(migrator, database) function.

The file stem is a pure, deterministic function of the version component and a short stable digest of the canonicalised diff: the same diff yields the same name, and distinct diffs within a directory yield distinct names. Generation never overwrites an existing file, so a scientist can edit a generated script and have the edited content applied verbatim.

Added in version 2.4.

author:

Bulgheroni Antonio (antonio.bulgheroni@ec.europa.eu)

Functions

content_checksum(body)

Return the sha-256 checksum of a script body, ignoring the checksum line.

diff_digest(diff)

Return a short stable digest of the canonicalised diff.

load_script(path)

Parse a migration script descriptor from a file on disk.

recorded_checksum(path)

Return the checksum recorded in a script header, if present.

render_script(diff, version)

Render an editable migration-script module for a diff.

script_name(diff, version)

Compute the deterministic, injective file stem for a migration script.

write_script(directory, name, body)

Write a migration script, refusing to overwrite an existing file.

Classes

MigrationScript(version, name, path, checksum)

A generated or discovered migration script.

class mafw.db.migration.script.MigrationScript(version: str, name: str, path: Path, checksum: str, requires_review: bool = False)[source]

Bases: object

A generated or discovered migration script.

Parameters:
  • version (str) – The sortable version identifier (for example a zero-padded sequence number).

  • name (str) – The file stem, deterministic from the diff.

  • path (Path) – The absolute path of the script on disk.

  • checksum (str) – The sha-256 checksum of the canonical script content.

  • requires_review (bool) – Whether the script still carries a pending review-required flag for one or more unsupported/destructive operations. A script that requires review is refused by the applier until a scientist has inspected it and cleared the flag.

Added in version 2.4.

mafw.db.migration.script._operation_lines(diff: SchemaDiff) → list[str][source]

Render the ordered operation statements for the supported differences.

Only the supported (safe, additive) differences are emitted as executable operations. Unsupported/destructive differences are rendered separately as commented, non-executing stubs by _review_lines().

Parameters:

diff (SchemaDiff) – The schema diff whose supported differences are rendered.

Returns:

The list of Python source lines inside the migrate function.

Return type:

list[str]

mafw.db.migration.script._review_lines(diff: SchemaDiff) → list[str][source]

Render commented stubs for the unsupported/destructive differences.

Each unsupported difference becomes a loud, non-executing comment block that states the detected change, the data-loss risk, and a suggested (commented) playhouse.migrate call. The scientist must complete and uncomment the operation by hand, then clear __migration_requires_review__ to apply it.

Parameters:

diff (SchemaDiff) – The schema diff whose unsupported differences are rendered.

Returns:

The list of Python source lines inside the review section.

Return type:

list[str]

mafw.db.migration.script.content_checksum(body: str) → str[source]

Return the sha-256 checksum of a script body, ignoring the checksum line.

The checksum covers the canonical content of the file so that an unrelated change to the recorded checksum line cannot mask a real content change.

Parameters:

body (str) – The full script body.

Returns:

The sha-256 hexadecimal digest of the canonical content.

Return type:

str

mafw.db.migration.script.diff_digest(diff: SchemaDiff) → str[source]

Return a short stable digest of the canonicalised diff.

Parameters:

diff (SchemaDiff) – The schema diff to digest.

Returns:

The first twelve hexadecimal characters of the sha-256 digest.

Return type:

str

mafw.db.migration.script.load_script(path: Path) → MigrationScript[source]

Parse a migration script descriptor from a file on disk.

Parameters:

path (Path) – The path to the migration script.

Returns:

The parsed descriptor.

Return type:

MigrationScript

Raises:

ValueError – if the file lacks a parseable version header.

mafw.db.migration.script.recorded_checksum(path: Path) → str | None[source]

Return the checksum recorded in a script header, if present.

Parameters:

path (Path) – The path to the migration script.

Returns:

The recorded checksum, or None when absent.

Return type:

str | None

mafw.db.migration.script.render_script(diff: SchemaDiff, version: str) → str[source]

Render an editable migration-script module for a diff.

The generated module declares its version and checksum, documents the change, and exposes a migrate(migrator, database) function. Supported (safe, additive) differences are emitted as executable operations. If the diff contains any unsupported/destructive difference, the module additionally declares __migration_requires_review__ = True and renders a loud, commented review section: the service refuses to apply such a script until a scientist has reviewed it, completed the operations by hand, and cleared the flag. The body is a template a scientist may freely edit before applying.

Parameters:
  • diff (SchemaDiff) – The schema diff to render.

  • version (str) – The sortable version component.

Returns:

The full script body as text.

Return type:

str

mafw.db.migration.script.script_name(diff: SchemaDiff, version: str) → str[source]

Compute the deterministic, injective file stem for a migration script.

The stem combines the version component with a short stable digest of the canonicalised diff. script_name is a pure function: the same diff and version yield the same name, and distinct diffs yield distinct names.

Parameters:
  • diff (SchemaDiff) – The schema diff the script will carry.

  • version (str) – The sortable version component.

Returns:

The file stem (without the .py extension).

Return type:

str

mafw.db.migration.script.write_script(directory: Path, name: str, body: str) → MigrationScript[source]

Write a migration script, refusing to overwrite an existing file.

If a file with the target name already exists, its bytes are preserved unchanged and the existing script is returned (parsed from disk). This is what lets a scientist edit a generated script and keep the edited content.

Parameters:
  • directory (Path) – The resolved migration directory.

  • name (str) – The file stem (without extension).

  • body (str) – The script body to write when the file does not yet exist.

Returns:

The written or pre-existing migration script descriptor.

Return type:

MigrationScript

mafw.db.migration.script._MIGRATOR_OPERATIONS: tuple[str, ...] = ('add_column(table, column_name, field, allow_not_null=False)', 'drop_column(table, column_name, cascade=True)', 'rename_column(table, old_name, new_name)', 'add_not_null(table, column)', 'drop_not_null(table, column)', 'add_column_default(table, column, default)', 'drop_column_default(table, column)', 'alter_column_type(table, column, field, cast=None)', 'rename_table(old_name, new_name)', 'add_index(table, columns, unique=False, using=None, where=None, nulls_distinct=None, name=None)', 'drop_index(table, index_name)', 'add_unique(table, *column_names)', 'add_constraint(table, name, constraint)', 'drop_constraint(table, name)', 'add_foreign_key_constraint(table, column_name, rel, rel_column, ...)', 'drop_foreign_key_constraint(table, column_name)', 'drop_table(table, safe=False, cascade=False, schema=None)')

Reference list of the operations offered by the per-backend playhouse.migrate.SchemaMigrator, embedded verbatim in the docstring of every generated script so a reviewing scientist has the exact signatures to hand while completing a migration. Mirrors the installed Peewee 4.5.3 API and the documentation at https://docs.peewee-orm.com/en/latest/peewee/db_tools.html#module-playhouse.migrate

mafw.db.migration.script._UNSUPPORTED_HINTS: dict[str, str] = {'add_not_null_column': 'migrator.add_column({table!r}, {column!r}, <field_with_default>)  # backfill data first', 'alter_column_type': 'migrator.alter_column_type({table!r}, {column!r}, <new_field>)', 'alter_nullability': 'migrator.add_not_null({table!r}, {column!r})  # or drop_not_null(...)', 'drop_column': 'migrator.drop_column({table!r}, {column!r})', 'drop_index': "migrator.drop_index({table!r}, '<index_name>')  # index on ({column})", 'drop_table': 'migrator.drop_table({table!r})'}

Suggested, intentionally non-executing migrator calls for each unsupported difference kind. The scientist must uncomment and complete the operation by hand, because the service never performs a destructive change automatically.

mafw.db.migration.script._VERSION_RE = re.compile('^__migration_version__\\s*=\\s*[\'\\"](?P<version>[^\'\\"]+)[\'\\"]', re.MULTILINE)

Regular expression used to parse the metadata header of a generated script.