diff options
-rw-r--r-- | CHANGES | 17 | ||||
-rw-r--r-- | alembic/operations.py | 18 | ||||
-rw-r--r-- | alembic/script.py | 4 | ||||
-rw-r--r-- | alembic/util.py | 12 | ||||
-rw-r--r-- | docs/build/conf.py | 4 | ||||
-rw-r--r-- | docs/build/tutorial.rst | 19 | ||||
-rw-r--r-- | tests/test_op.py | 20 |
7 files changed, 84 insertions, 10 deletions
@@ -3,6 +3,23 @@ - [bug] setup.py won't install argparse if on Python 2.7/3.2 +- [feature] script_location can be interpreted + by pkg_resources.resource_filename(), if + it is a non-absolute URI that contains + colons. This scheme is the same + one used by Pyramid. [#29] + +- [feature] added missing support for + onupdate/ondelete flags for + ForeignKeyConstraint, courtesy Giacomo Bagnoli + +- [bug] fixed a regression regarding an autogenerate + error message, as well as various glitches + in the Pylons sample template. The Pylons sample + template requires that you tell it where to + get the Engine from now. courtesy + Marcin Kuzminski [#30] + 0.2.1 ===== - [bug] Fixed the generation of CHECK constraint, diff --git a/alembic/operations.py b/alembic/operations.py index 1bbe5a1..22f260c 100644 --- a/alembic/operations.py +++ b/alembic/operations.py @@ -51,7 +51,8 @@ class Operations(object): alembic.op._remove_proxy() def _foreign_key_constraint(self, name, source, referent, - local_cols, remote_cols): + local_cols, remote_cols, + onupdate=None, ondelete=None): m = schema.MetaData() t1 = schema.Table(source, m, *[schema.Column(n, NULLTYPE) for n in local_cols]) @@ -61,7 +62,9 @@ class Operations(object): f = schema.ForeignKeyConstraint(local_cols, ["%s.%s" % (referent, n) for n in remote_cols], - name=name + name=name, + onupdate=onupdate, + ondelete=ondelete ) t1.append_constraint(f) @@ -315,7 +318,7 @@ class Operations(object): def create_foreign_key(self, name, source, referent, local_cols, - remote_cols): + remote_cols, onupdate=None, ondelete=None): """Issue a "create foreign key" instruction using the current migration context. @@ -349,12 +352,19 @@ class Operations(object): source table. :param remote_cols: a list of string column names in the remote table. + :param onupdate: Optional string. If set, emit ON UPDATE <value> when + issuing DDL for this constraint. Typical values include CASCADE, + DELETE and RESTRICT. + :param ondelete: Optional string. If set, emit ON DELETE <value> when + issuing DDL for this constraint. Typical values include CASCADE, + DELETE and RESTRICT. """ self.impl.add_constraint( self._foreign_key_constraint(name, source, referent, - local_cols, remote_cols) + local_cols, remote_cols, + onupdate=onupdate, ondelete=ondelete) ) def create_unique_constraint(self, name, source, local_cols, **kw): diff --git a/alembic/script.py b/alembic/script.py index f9e0224..952b572 100644 --- a/alembic/script.py +++ b/alembic/script.py @@ -30,7 +30,9 @@ class ScriptDirectory(object): @classmethod def from_config(cls, config): return ScriptDirectory( - config.get_main_option('script_location'), + util.coerce_resource_to_filename( + config.get_main_option('script_location') + ), file_template = config.get_main_option( 'file_template', _default_file_template) diff --git a/alembic/util.py b/alembic/util.py index 3ae15f9..3599531 100644 --- a/alembic/util.py +++ b/alembic/util.py @@ -111,6 +111,18 @@ def create_module_class_proxy(cls, globals_, locals_): else: attr_names.add(methname) +def coerce_resource_to_filename(fname): + """Interpret a filename as either a filesystem location or as a package resource. + + Names that are non absolute paths and contain a colon + are interpreted as resources and coerced to a file location. + + """ + if not os.path.isabs(fname) and ":" in fname: + import pkg_resources + fname = pkg_resources.resource_filename(*fname.split(':')) + return fname + def status(_statmsg, fn, *arg, **kw): msg(_statmsg + "...", False) try: diff --git a/docs/build/conf.py b/docs/build/conf.py index 165fa60..44dde4b 100644 --- a/docs/build/conf.py +++ b/docs/build/conf.py @@ -206,4 +206,6 @@ latex_documents = [ #{'python': ('http://docs.python.org/3.2', None)} -intersphinx_mapping = {'sqla':('http://www.sqlalchemy.org/docs/', None)} +intersphinx_mapping = { + 'sqla':('http://www.sqlalchemy.org/docs/', None), +} diff --git a/docs/build/tutorial.rst b/docs/build/tutorial.rst index c5bee93..8e47f1b 100644 --- a/docs/build/tutorial.rst +++ b/docs/build/tutorial.rst @@ -114,7 +114,7 @@ The file generated with the "generic" configuration looks like:: [alembic] # path to migration scripts - script_location = %(here)s/alembic + script_location = alembic # template used to generate migration files # file_template = %%(rev)s_%%(slug)s @@ -165,11 +165,22 @@ This file contains the following features: * ``[alembic]`` - this is the section read by Alembic to determine configuration. Alembic itself does not directly read any other areas of the file. -* ``script_location`` - this is the location of the Alembic environment, relative to - the current directory, unless the path is an absolute file path. +* ``script_location`` - this is the location of the Alembic environment. It is normally + specified as a filesystem location, either relative or absolute. If the location is + a relative path, it's interpreted as relative to the current directory. + This is the only key required by Alembic in all cases. The generation of the .ini file by the command ``alembic init alembic`` automatically placed the - directory name ``alembic`` here. + directory name ``alembic`` here. The special variable ``%(here)s`` can also be used, + as in ``%(here)s/alembic``. + + For support of applications that package themselves into .egg files, the value can + also be specified + as a `package resource <http://packages.python.org/distribute/pkg_resources.html>`_, in which + case ``resource_filename()`` is used to find the file (new in 0.2.2). Any non-absolute + URI which contains colons is interpreted here as a resource name, rather than + a straight filename. + * ``file_template`` - this is the naming scheme used to generate new migration files. The value present is the default, so is commented out. The two tokens available are ``%%(rev)s`` and ``%%(slug)s``, where ``%%(slug)s`` is a truncated string derived diff --git a/tests/test_op.py b/tests/test_op.py index 8af4711..58f19cb 100644 --- a/tests/test_op.py +++ b/tests/test_op.py @@ -154,6 +154,26 @@ def test_add_foreign_key(): "REFERENCES t2 (bat, hoho)" ) +def test_add_foreign_key_onupdate(): + context = op_fixture() + op.create_foreign_key('fk_test', 't1', 't2', + ['foo', 'bar'], ['bat', 'hoho'], + onupdate='CASCADE') + context.assert_( + "ALTER TABLE t1 ADD CONSTRAINT fk_test FOREIGN KEY(foo, bar) " + "REFERENCES t2 (bat, hoho) ON UPDATE CASCADE" + ) + +def test_add_foreign_key_ondelete(): + context = op_fixture() + op.create_foreign_key('fk_test', 't1', 't2', + ['foo', 'bar'], ['bat', 'hoho'], + ondelete='CASCADE') + context.assert_( + "ALTER TABLE t1 ADD CONSTRAINT fk_test FOREIGN KEY(foo, bar) " + "REFERENCES t2 (bat, hoho) ON DELETE CASCADE" + ) + def test_add_check_constraint(): context = op_fixture() op.create_check_constraint( |