sqlalchemy / sqlalchemy/alembic

add rev_id generator function feature to environment.configure(), will apply to revision, merge

Open
#1,732 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

awaiting info use case
Dominant language
Python
Stars
4.4k
Forks
375
PR merge metrics
No merged PRs in 30d

Description

Describe the use case

The merge command should support the process_revision_directives parameter in its programmatic API, consistent with the revision command.

Currently, while both commands support revision_environment (which runs env.py), only the revision command accepts a programmatic process_revision_directives parameter. This creates an API
inconsistency when using Alembic programmatically to customize revision generation logic for merge operations.

Databases / Backends / Drivers targeted

All databases - this is a general Alembic API feature request.

Example Use

Current behavior - revision command (works):

  from alembic import command
  from alembic.config import Config

  config = Config("alembic.ini")

  def my_process_revision_directives(context, revision, directives):
      """Custom revision ID generation logic"""
      for directive in directives:
          directive.rev_id = generate_custom_id()  # Custom logic

This works - process_revision_directives parameter is supported

  command.revision(
      config,
      message="Add new feature",
      process_revision_directives=my_process_revision_directives
  )

Desired behavior - merge command (currently doesn't work):

  # This fails with TypeError - process_revision_directives is not accepted
  command.merge(
      config,
      revisions=("head1", "head2"),
      message="Merge branches",
      process_revision_directives=my_process_revision_directives  # ❌ Not supported
  )

Current workaround:

Users must configure the hook in env.py, which affects all operations:

  # env.py
  def process_revision_directives(context, revision, directives):
      # This applies to ALL revision/merge commands
      for directive in directives:
          directive.rev_id = generate_custom_id()

  context.configure(
      process_revision_directives=process_revision_directives
  )

This workaround doesn't allow per-command customization when using the programmatic API.

Proposed API:

  def merge(
      config: Config,
      revisions: _RevIdType,
      message: Optional[str] = None,
      branch_label: Optional[_RevIdType] = None,
      rev_id: Optional[str] = None,
      process_revision_directives: Optional[ProcessRevisionDirectiveFn] = None,  # NEW
  ) -> Optional[Script]:
      """
      :param process_revision_directives: optional callable that allows
       programmatic customization of the revision directives. Same signature
       as the callable described at
       :paramref:`.EnvironmentContext.configure.process_revision_directives`
      """
      # Implementation already uses RevisionContext internally,
      # just need to accept and pass through the parameter

Use cases:

  1. Different logic for merges vs regular revisions: Apply special revision ID schemes or metadata only to merge commits
  2. CI/CD automation: Programmatic scripts that customize merge behavior without modifying env.py
  3. Multi-tenant environments: Different revision ID generation based on runtime context

Additional context

  • The merge command already uses RevisionContext internally (since 1.12.0 when revision_environment support was added via #1299)
  • The implementation would be minimal - just accepting and passing through the parameter
  • This would make the API consistent between revision and merge commands
  • The parameter would be optional and backward-compatible

Reference:

  • alembic/command.py::revision() - Lines 194-320 (already supports this parameter)
  • alembic/command.py::merge() - Lines 382-439 (should support this parameter)
  • alembic/autogenerate/api.py::RevisionContext - Already supports process_revision_directives

Versions.

  • OS: macOS (but applies to all platforms)
  • Python: 3.9+
  • Alembic: 1.16.5 (latest)
  • SQLAlchemy: 1.4+/2.0+
  • Database: All
  • DBAPI: All

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start in alembic/command.py, comparing revision() around lines 194-320 with merge() around lines 382-439. Trace how merge() constructs its RevisionContext and how alembic/autogenerate/api.py handles process_revision_directives. Done means the merge API accepts and forwards the optional callback consistently, with coverage for the new parameter and existing behavior preserved.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, sqlalchemy
Domain
backend-api-design, database
Issue type
Feature
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
55/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.