"""
+ imports = None
+ """A ``set()`` which contains string Python import directives.
+
+ The directives are to be rendered into the ``${imports}`` section
+ of a script template. The set is normally empty and can be modified
+ within hooks such as the :paramref:`.EnvironmentContext.configure.render_item`
+ hook.
+
+ .. versionadded:: 0.8.3
+
+ .. seealso::
+
+ :ref:`autogen_render_types`
+
+ """
+
migration_context = None
"""The :class:`.MigrationContext` established by the ``env.py`` script."""
self.connection = self.migration_context.bind
self.dialect = self.migration_context.dialect
- self._imports = set()
+ self.imports = set()
self.opts = opts
self._has_batch = False
if getattr(migration_script, '_needs_render', False):
autogen_context = self._last_autogen_context
- autogen_context._imports = set()
+ # clear out existing imports if we are doing multiple
+ # renders
+ autogen_context.imports = set()
if migration_script.imports:
- autogen_context._imports.union_update(migration_script.imports)
+ autogen_context.imports.union_update(migration_script.imports)
render._render_python_into_templatevars(
autogen_context, migration_script, template_args
)
def _render_python_into_templatevars(
autogen_context, migration_script, template_args):
- imports = autogen_context._imports
+ imports = autogen_context.imports
for upgrade_ops, downgrade_ops in zip(
migration_script.upgrade_ops_list,
return rendered
mod = type(type_).__module__
- imports = autogen_context._imports
+ imports = autogen_context.imports
if mod.startswith("sqlalchemy.dialects"):
dname = re.match(r"sqlalchemy\.dialects\.(\w+)", mod).group(1)
if imports is not None:
``__repr__()`` method, which is invoked when we call it against ``"%r"``.
The callable we use for :paramref:`.EnvironmentContext.configure.render_item`
-can also add imports to our migration script. The ``autogen_context`` passed in
-contains an entry called ``autogen_context['imports']``, which is a Python
+can also add imports to our migration script. The :class:`.AutogenContext` passed in
+contains a datamember called :attr:`.AutogenContext.imports`, which is a Python
``set()`` for which we can add new imports. For example, if ``MySpecialType``
were in a module called ``mymodel.types``, we can add the import for it
as we encounter the type::
if type_ == 'type' and isinstance(obj, MySpecialType):
# add import for this type
- autogen_context['imports'].add("from mymodel import types")
+ autogen_context.imports.add("from mymodel import types")
return "types.%r" % obj
# default rendering for other objects
return False
+.. versionchanged:: 0.8 The ``autogen_context`` data member passed to
+ the ``render_item`` callable is now an instance of :class:`.AutogenContext`.
+
+.. versionchanged:: 0.8.3 The "imports" data member of the autogen context
+ is restored to the new :class:`.AutogenContext` object as
+ :attr:`.AutogenContext.imports`.
+
The finished migration script will include our imports where the
``${imports}`` expression is used, producing output such as::
.. changelog::
:version: 0.8.3
+ .. change::
+ :tags: bug, autogenerate
+ :tickets: 332
+
+ Fixed an 0.8 regression whereby the "imports" dictionary member of
+ the autogen context was removed; this collection is documented in the
+ "render custom type" documentation as a place to add new imports.
+ The member is now known as
+ :attr:`.AutogenContext.imports` and the documentation is repaired.
+
.. change::
:tags: bug, batch
:tickets: 333
op.drop_table('item')
### end Alembic commands ###""")
+ def test_imports_maintined(self):
+ template_args = {}
+ self.context.opts['render_as_batch'] = True
+
+ def render_item(type_, col, autogen_context):
+ autogen_context.imports.add(
+ "from mypackage import my_special_import"
+ )
+ autogen_context.imports.add(
+ "from foobar import bat"
+ )
+
+ self.context.opts["render_item"] = render_item
+ autogenerate._render_migration_diffs(self.context, template_args)
+ eq_(
+ set(
+ template_args['imports'].split("\n")
+ ),
+ set([
+ "from foobar import bat",
+ "from mypackage import my_special_import"
+ ])
+ )
+
class AutogenerateDiffTestWSchema(ModelOne, AutogenTest, TestBase):
__only_on__ = 'postgresql'
def test_render_custom(self):
+ class MySpecialType(Integer):
+ pass
+
def render(type_, obj, context):
if type_ == "foreign_key":
return None
if type_ == "column":
if obj.name == "y":
return None
+ elif obj.name == "q":
+ return False
else:
return "col(%s)" % obj.name
+ if type_ == "type" and isinstance(obj, MySpecialType):
+ context.imports.add("from mypackage import MySpecialType")
+ return "MySpecialType()"
+
return "render:%s" % type_
self.autogen_context.opts.update(
t = Table('t', MetaData(),
Column('x', Integer),
Column('y', Integer),
+ Column('q', MySpecialType()),
PrimaryKeyConstraint('x'),
ForeignKeyConstraint(['x'], ['y'])
)
result,
"sa.create_table('t',"
"col(x),"
+ "sa.Column('q', MySpecialType(), nullable=True),"
"render:primary_key)"
)
+ eq_(
+ self.autogen_context.imports,
+ set(['from mypackage import MySpecialType'])
+ )
def test_render_modify_type(self):
op_obj = ops.AlterColumnOp(
autogenerate.render._repr_type(type_, self.autogen_context),
"mysql.VARCHAR(charset='utf8', national=True, length=20)"
)
- eq_(self.autogen_context._imports,
+ eq_(self.autogen_context.imports,
set(['from sqlalchemy.dialects import mysql'])
)