From f3c7902789e9923a465228682d7565e2b86ce84c Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 16 Nov 2011 17:15:38 -0500 Subject: [PATCH] - requires_connection() -> is_offline_mode() - move "offline" tranasctional markers to env.py script - move online/offline sections into separate functions in env.py scripts - move context initial logging to the __init__ method --- alembic/context.py | 58 ++++++++++++++++++++++--------- alembic/templates/generic/env.py | 41 ++++++++++++++++------ alembic/templates/multidb/env.py | 59 ++++++++++++++++++++++---------- alembic/templates/pylons/env.py | 28 +++++++++++++-- tests/test_sql_script.py | 1 + 5 files changed, 138 insertions(+), 49 deletions(-) diff --git a/alembic/context.py b/alembic/context.py index 4bc6b032..20491f39 100644 --- a/alembic/context.py +++ b/alembic/context.py @@ -47,6 +47,12 @@ class Context(object): transactional_ddl, self.output_buffer ) + log.info("Context impl %s.", self.impl.__class__.__name__) + if self.as_sql: + log.info("Generating static SQL") + log.info("Will assume %s DDL.", + "transactional" if self.impl.transactional_ddl + else "non-transactional") def _current_rev(self): if self.as_sql: @@ -74,15 +80,6 @@ class Context(object): ) def run_migrations(self, **kw): - log.info("Context impl %s.", self.impl.__class__.__name__) - if self.as_sql: - log.info("Generating static SQL") - log.info("Will assume %s DDL.", - "transactional" if self.impl.transactional_ddl - else "non-transactional") - - if self.as_sql and self.impl.transactional_ddl: - self.impl.static_output("BEGIN;") current_rev = rev = False for change, prev_rev, rev in self._migrations_fn( @@ -106,9 +103,6 @@ class Context(object): if self.as_sql and not rev: _version.drop(self.connection) - if self.as_sql and self.impl.transactional_ddl: - self.impl.static_output("COMMIT;") - def execute(self, sql): self.impl._exec(sql) @@ -171,18 +165,35 @@ def _clear(): _context = _script = None _context_opts = {} -def requires_connection(): - """Return True if the current migrations environment should have - an active database connection. +def is_offline_mode(): + """Return True if the current migrations environment + is running in "offline mode". - Currently, this is ``True`` or ``False`` depending + This is ``True`` or ``False`` depending on the the ``--sql`` flag passed. This function does not require that the :class:`.Context` has been configured. """ - return not _context_opts.get('as_sql', False) + return _context_opts.get('as_sql', False) + +def is_transactional_ddl(): + """Return True if the context is configured to expect a + transactional DDL capable backend. + + This defaults to the type of database in use, and + can be overridden by the ``transactional_ddl`` argument + to :func:`.configure` + + This function requires that a :class:`.Context` has first been + made available via :func:`.configure`. + + """ + return get_context().impl.transactional_ddl + +def requires_connection(): + return not is_offline_mode() def get_head_revision(): """Return the hex identifier of the 'head' revision. @@ -373,5 +384,18 @@ def get_context(): raise Exception("No context has been configured yet.") return _context +def get_bind(): + """Return the current 'bind'. + + In "online" mode, this is the + :class:`sqlalchemy.engine.Connection` currently being used + to emit SQL to the database. + + This function requires that a :class:`.Context` has first been + made available via :func:`.configure`. + + """ + return get_context().bind + def get_impl(): return get_context().impl \ No newline at end of file diff --git a/alembic/templates/generic/env.py b/alembic/templates/generic/env.py index 8f5018f1..423c53e6 100644 --- a/alembic/templates/generic/env.py +++ b/alembic/templates/generic/env.py @@ -10,26 +10,39 @@ config = context.config # This line sets up loggers basically. fileConfig(config.config_file_name) - # other values from the config, defined by the needs of env.py, # can be acquired: # my_important_option = config.get_main_option("my_important_option") # ... etc. -# if we're running in --sql mode, do everything connectionless. -# We only need a URL, not an Engine, thereby not even requiring -# the DBAPI be installed, though an actual Engine would of course be fine as well. -if not context.requires_connection(): +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ url = config.get_main_option("sqlalchemy.url") context.configure(url=url) + + if context.is_transactional_ddl(): + context.execute("BEGIN") context.run_migrations() + if context.is_transactional_ddl(): + context.execute("COMMIT") -# otherwise we need to make a connection. -else: +def run_migrations_online(): + """Run migrations in 'online' mode. - # Produce a SQLAlchemy engine using the key/values - # within the "alembic" section of the documentation, - # other otherwise what config_ini_section points to. + In this scenario we need to create an Engine + and associate a connection with the context. + + """ engine = engine_from_config( config.get_section(config.config_ini_section), prefix='sqlalchemy.') @@ -42,4 +55,10 @@ else: trans.commit() except: trans.rollback() - raise \ No newline at end of file + raise + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() + diff --git a/alembic/templates/multidb/env.py b/alembic/templates/multidb/env.py index e561e9be..1ffa597c 100644 --- a/alembic/templates/multidb/env.py +++ b/alembic/templates/multidb/env.py @@ -12,22 +12,26 @@ logging.fileConfig(options.config_file) # databases. db_names = options.get_main_option('databases') -# set aside if we need engines or just URLs to do this. -need_engine = context.requires_connection() - -# load up SQLAlchemy engines or URLs. -engines = {} -for name in re.split(r',\s*', db_names): - engines[name] = rec = {} - if need_engine: - rec['engine'] = engine_from_config(context.config.get_section(name), - prefix='sqlalchemy.') - else: +def run_migrations_offline(): + """Run migrations in 'offline' mode. + + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ + # for the --sql use case, run migrations for each URL into + # individual files. + + engines = {} + for name in re.split(r',\s*', db_names): + engines[name] = rec = {} rec['url'] = context.config.get_section_option(name, "sqlalchemy.url") -# for the --sql use case, run migrations for each URL into -# individual files. -if not need_engine: for name, rec in engines.items(): file_ = "%s.sql" % name sys.stderr.write("Writing output to %s\n" % file_) @@ -37,9 +41,23 @@ if not need_engine: ) context.run_migrations(engine=name) -# for the direct-to-DB use case, start a transaction on all -# engines, then run all migrations, then commit all transactions. -else: +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ + + # for the direct-to-DB use case, start a transaction on all + # engines, then run all migrations, then commit all transactions. + + engines = {} + for name in re.split(r',\s*', db_names): + engines[name] = rec = {} + rec['engine'] = engine_from_config(context.config.get_section(name), + prefix='sqlalchemy.') + for name, rec in engines.items(): engine = rec['engine'] rec['connection'] = conn = engine.connect() @@ -67,4 +85,9 @@ else: except: for rec in engines.values(): rec['transaction'].rollback() - raise \ No newline at end of file + raise + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/alembic/templates/pylons/env.py b/alembic/templates/pylons/env.py index 2a3d9972..2726f906 100644 --- a/alembic/templates/pylons/env.py +++ b/alembic/templates/pylons/env.py @@ -23,12 +23,29 @@ except: # customize this section for non-standard engine configurations. meta = __import__("%s.model.meta" % config['pylons.package']).model.meta +def run_migrations_offline(): + """Run migrations in 'offline' mode. -if not context.requires_connection(): + This configures the context with just a URL + and not an Engine, though an Engine is acceptable + here as well. By skipping the Engine creation + we don't even need a DBAPI to be available. + + Calls to context.execute() here emit the given string to the + script output. + + """ context.configure( dialect_name=meta.engine.name) context.run_migrations() -else: + +def run_migrations_online(): + """Run migrations in 'online' mode. + + In this scenario we need to create an Engine + and associate a connection with the context. + + """ connection = meta.engine.connect() context.configure_connection(connection) trans = connection.begin() @@ -37,4 +54,9 @@ else: trans.commit() except: trans.rollback() - raise \ No newline at end of file + raise + +if context.is_offline_mode(): + run_migrations_offline() +else: + run_migrations_online() diff --git a/tests/test_sql_script.py b/tests/test_sql_script.py index 54538a10..3e4dc327 100644 --- a/tests/test_sql_script.py +++ b/tests/test_sql_script.py @@ -55,3 +55,4 @@ def test_stamp(): with capture_context_buffer() as buf: command.stamp(cfg, "head", sql=True) assert "UPDATE alembic_version SET version_num='%s';" % c in buf.getvalue() + -- 2.47.2