]> git.ipfire.org Git - thirdparty/sqlalchemy/alembic.git/commitdiff
- the original rationale for defaulting the user-defined namespace
authorMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Oct 2014 17:14:06 +0000 (13:14 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Tue, 21 Oct 2014 17:14:06 +0000 (13:14 -0400)
to "sa." was to force users to deal with making sure their custom
types came from a fixed module somewhere.  However, it's not worth
defending this rationale.

The default value of the
:paramref:`.EnvironmentContext.configure.user_module_prefix`
parameter is **no longer the same as the SQLAlchemy prefix**.
When omitted, user-defined types will now use the ``__module__``
attribute of the type class itself when rendering in an
autogenerated module.

fixes #229

alembic/autogenerate/render.py
alembic/environment.py
docs/build/changelog.rst
docs/build/conf.py
docs/build/tutorial.rst
tests/test_autogen_render.py

index 7d9817a4266d957469bce88d772c315566495755..67fb2ca76487a6affbc5e228d7e25b1b62d6cbb4 100644 (file)
@@ -298,10 +298,10 @@ def _modify_col(tname, cname,
     return text
 
 
-def _user_autogenerate_prefix(autogen_context):
+def _user_autogenerate_prefix(autogen_context, target):
     prefix = autogen_context['opts']['user_module_prefix']
     if prefix is None:
-        return _sqlalchemy_autogenerate_prefix(autogen_context)
+        return "%s." % target.__module__
     else:
         return prefix
 
@@ -386,7 +386,7 @@ def _repr_type(type_, autogen_context):
         prefix = _sqlalchemy_autogenerate_prefix(autogen_context)
         return "%s%r" % (prefix, type_)
     else:
-        prefix = _user_autogenerate_prefix(autogen_context)
+        prefix = _user_autogenerate_prefix(autogen_context, type_)
         return "%s%r" % (prefix, type_)
 
 
index 7df13bfbf8b8a6dcdef43c145adf2d9ebbe98cb7..1dfb00065c127d4d78b1e3a00666ac1e8dafc475 100644 (file)
@@ -604,10 +604,18 @@ class EnvironmentContext(object):
         :param user_module_prefix: When autogenerate refers to a SQLAlchemy
          type (e.g. :class:`.TypeEngine`) where the module name is not
          under the ``sqlalchemy`` namespace, this prefix will be used
-         within autogenerate, if non-``None``; if left at its default of
-         ``None``, the
-         :paramref:`.EnvironmentContext.configure.sqlalchemy_module_prefix`
-         is used instead.
+         within autogenerate.  If left at its default of
+         ``None``, the ``__module__`` attribute of the type is used to
+         render the import module.   It's a good practice to set this
+         and to have all custom types be available from a fixed module space,
+         in order to future-proof migration files against reorganizations
+         in modules.
+
+         .. versionchanged:: 0.7.0
+            :paramref:`.EnvironmentContext.configure.user_module_prefix`
+            no longer defaults to the value of
+            :paramref:`.EnvironmentContext.configure.sqlalchemy_module_prefix`
+            when left at ``None``; the ``__module__`` attribute is now used.
 
          .. versionadded:: 0.6.3 added
             :paramref:`.EnvironmentContext.configure.user_module_prefix`
index dc87462e754f3a4f4a2c9fddabb05d478732015d..8702cacd4f61d2159d24d67d519f901adbeb97e5 100644 (file)
@@ -5,6 +5,17 @@ Changelog
 .. changelog::
     :version: 0.7.0
 
+    .. change::
+      :tags: changed, autogenerate
+      :tickets: 229
+
+      The default value of the
+      :paramref:`.EnvironmentContext.configure.user_module_prefix`
+      parameter is **no longer the same as the SQLAlchemy prefix**.
+      When omitted, user-defined types will now use the ``__module__``
+      attribute of the type class itself when rendering in an
+      autogenerated module.
+
     .. change::
       :tags: bug, templates
       :tickets: 234
index 80a23bc6d7e0e685365ec96200f37824f433edbb..9e0f077ca973cccc7dfc2e2f56826f03c4a37256 100644 (file)
@@ -34,7 +34,7 @@ extensions = ['sphinx.ext.autodoc', 'sphinx.ext.intersphinx',
                 'changelog', 'sphinx_paramlinks']
 
 # tags to sort on inside of sections
-changelog_sections = ["feature", "bug", "moved", "changed", "removed"]
+changelog_sections = ["changed", "feature", "bug", "moved", "removed"]
 
 changelog_render_ticket = "https://bitbucket.org/zzzeek/alembic/issue/%s/"
 changelog_render_pullreq = "https://bitbucket.org/zzzeek/alembic/pull-request/%s"
index 82e7284b0c6ec56f59273df0ef3ece871837219c..012bcc5dbe6c47950398bfca64283552cdcc9469 100644 (file)
@@ -716,17 +716,31 @@ When using :paramref:`.EnvironmentContext.configure.render_item`, note that
 we deliver not just the reproduction of the type, but we can also deliver the
 "module prefix", which is a module namespace from which our type can be found
 within our migration script.  When Alembic renders SQLAlchemy types, it will
-typically use the value of :paramref:`.EnvironmentContext.configure.sqlalchemy_module_prefix`,
+typically use the value of
+:paramref:`.EnvironmentContext.configure.sqlalchemy_module_prefix`,
 which defaults to ``"sa."``, to achieve this::
 
     Column("my_column", sa.Integer())
 
 When we use a custom type that is not within the ``sqlalchemy.`` module namespace,
-by default Alembic will still use the ``"sa."`` prefix::
+by default Alembic will use the **value of __module__ for the custom type**::
 
-    Column("my_column", sa.MyCustomType())
+    Column("my_column", myapp.models.utils.types.MyCustomType())
 
-We can provide an alternate prefix here using the :paramref:`.EnvironmentContext.configure.user_module_prefix`
+Above, it seems our custom type is in a very specific location, based on
+the length of what ``__module__`` reports.   It's a good practice to
+not have this long name render into our migration scripts, as it means
+this long and arbitrary name will be hardcoded into all our migration
+scripts; instead, we should create a module that is
+explicitly for custom types that our migration files will use.  Suppose
+we call it ``myapp.migration_types``::
+
+  # myapp/migration_types.py
+
+  from myapp.models.utils.types import MyCustomType
+
+We can provide the name of this module to our autogenerate context using
+:paramref:`.EnvironmentContext.configure.user_module_prefix`
 option::
 
 
@@ -736,7 +750,7 @@ option::
         context.configure(
                     connection=connection,
                     target_metadata=target_metadata,
-                    user_module_prefix="mymodel.types",
+                    user_module_prefix="myapp.migration_types.",
                     # ...
                     )
 
@@ -744,7 +758,17 @@ option::
 
 Where we'd get a migration like::
 
-  Column("my_column", mymodel.types.MyCustomType())
+  Column("my_column", myapp.migration_types.MyCustomType())
+
+Now, when we inevitably refactor our application to move ``MyCustomType``
+somewhere else, we only need modify the ``myapp.migration_types`` module,
+instead of searching and replacing all instances within our migration scripts.
+
+.. versionchanged:: 0.7.0
+   :paramref:`.EnvironmentContext.configure.user_module_prefix`
+   no longer defaults to the value of
+   :paramref:`.EnvironmentContext.configure.sqlalchemy_module_prefix`
+   when left at ``None``; the ``__module__`` attribute is now used.
 
 .. versionadded:: 0.6.3 Added :paramref:`.EnvironmentContext.configure.user_module_prefix`.
 
index da17bd2a52fc9d05ee0a8713c285187bd2d676fa..889af2d537915b746f5d7bc50a1d3abbc8fcad76 100644 (file)
@@ -772,7 +772,7 @@ render:primary_key\n)"""
 
         eq_ignore_whitespace(
             autogenerate.render._repr_type(type_, autogen_context),
-            "sa.MyType()"
+            "tests.test_autogen_render.MyType()"
         )
 
     def test_repr_user_type_user_prefix_present(self):