1. Michael Bayer
  2. alembic
  3. Issues

Issues

Issue #19 resolved

Hard to use ops outside of alembic scripts

Wichert Akkerman
created an issue

I already have a simple upgrade framework that I want to keep using, but the operations implemented by alembic are very useful (and look saner than sqlalchemy-migrate), so I'm interested in using just the underlying alembic ops. This appears to be hard to do: the operations require a global context, but there is no API to configure that. This seems to at get some things going:

{{{

!python

from alembic import context from alembic.config import Config

config = Config(None) context._opts(config, None, fn=None) connection = meta.Session.connection() context.configure(connection=connection, target_metadata=meta.metadata) }}}

but it feels like API abuse to do it this way.

Comments (7)

  1. Michael Bayer repo owner

    The ops are based on a global context and that's not suitable to export as a standalone API right now. I had in mind folks could use the constructs inside of alembic.ddl though.

    But you want all the automatic crap. So the attached patch starts, you'd call:

    engine = create_engine("postgresql://scott:tiger@localhost/test", echo=True)
    connection = engine.connect()
    
    impl = ddl.ops_for_connection(connection)
    
    impl.add_column("sometable", Column("somecolumn", Integer))
    

    but then the code would have to be refactored such that all the "macro" behavior of alembic.op moves to alembic.ddl.impl.

    It would be better if you just moved your stuff from Migrate to Alembic fully.

  2. Wichert Akkerman reporter

    There are a few reasons I prefer our current upgrade framework:

    • we use introspection to figure out what steps to run, instead of relying on version numbers, which removes the need to keep track of version numbers or any other upgrade-machinery specific state. The upgrade mini-framework will simply run all known upgrade steps and rely on them to be idempotent.
    • it has a simple system where upgrade steps can declare specific environments, which works for non-SQL systems as well.

    In case you are interested our upgrade mini-framework is available at https://github.com/2style4you/s4u.upgrade . An example of hooking SQLAlchemy into it can be found at https://github.com/2style4you/s4u.sqlalchemy/blob/master/src/s4u/sqlalchemy/upgrade.py .

  3. Michael Bayer repo owner

    basically op.py would get everything moved to a new class `Operations`, then that can be instantiated for a particular impl, then we put some kind of helper function like `ops_for_connection()` to provide it. The tedious part then is having two of each function in op.py, the module level `add_column()` and the `Operations` level `add_column()`. We'd probably have op.add_column() document "see Operations.add_column()" for the documentation.

  4. Michael Bayer repo owner
    • changed milestone to 0.2.0

    OK you can see where I'm going with this in https://bitbucket.org/zzzeek/alembic-api-2-refactor. The only hard break is that "alembic.context" and "alembic.op" aren't modules anymore, so we'll make it 0.2 for that. Other than those two, which are established and torn down within the scope of a context manager, everything is non-global now and there is now a clean chain of objects with EnvironmentContext -> MigrationContext -> Operations. You can have MigrationContext without the EnvironmentContext also and I'll be making things more independent as this continues.

  5. Michael Bayer repo owner

    I've merged that fork back into the mainline. 0.1 is now branched off.

    It would be very helpful if you could review where I've gone with this, there's an arch diagram at http://alembic.readthedocs.org/en/latest/api.html . There's no longer reliance on globals, except for the "alembic.op" and "alembic.context" symbols made available to an env.py/migration script environment. I haven't built out tests for your case specifically yet, but you'd be looking to call `MigrationContext.configure()`, then pass that to the constructor of `Operations`. You shouldn't need the `EnvironmentContext` object at all. That's the goal anyway.

    Things are looking a bit more enterprisey but I'm hoping this exposes the maximum functionality in the most portable way. All tests are passing here and some field testing indicates everything seems to be working also.

    Anyway this is what 0.2 will look like unless you need me to make more adjustments, so let me know !

  6. Log in to comment