sqlalchemy / sqlalchemy/alembic
add rev_id generator function feature to environment.configure(), will apply to revision, merge
Nobody has claimed this yet.
- 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:
- Different logic for merges vs regular revisions: Apply special revision ID schemes or metadata only to merge commits
- CI/CD automation: Programmatic scripts that customize merge behavior without modifying env.py
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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