summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGES17
-rw-r--r--alembic/operations.py18
-rw-r--r--alembic/script.py4
-rw-r--r--alembic/util.py12
-rw-r--r--docs/build/conf.py4
-rw-r--r--docs/build/tutorial.rst19
-rw-r--r--tests/test_op.py20
7 files changed, 84 insertions, 10 deletions
diff --git a/CHANGES b/CHANGES
index 6bdca51..5fbd3bc 100644
--- a/CHANGES
+++ b/CHANGES
@@ -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(