summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMike Bayer <mike_mp@zzzcomputing.com>2010-03-11 17:43:55 +0000
committerMike Bayer <mike_mp@zzzcomputing.com>2010-03-11 17:43:55 +0000
commit757bf74ec040e4b98e97f0603858acc9a3066952 (patch)
tree7e9afc6f57daacaec8b77a9eefa91c895e08b019
parente45a14e6fc16ce2626a8dfdbf9d24921bf44cc28 (diff)
parent19de4da70f714a1918ed1370f9a4ac589f20b7de (diff)
downloadsqlalchemy-757bf74ec040e4b98e97f0603858acc9a3066952.tar.gz
merged default tip
-rw-r--r--CHANGES8
-rw-r--r--lib/sqlalchemy/schema.py7
-rw-r--r--lib/sqlalchemy/sql/util.py4
-rw-r--r--test/engine/test_metadata.py15
-rw-r--r--test/sql/test_generative.py5
-rw-r--r--test/sql/test_selectable.py14
6 files changed, 49 insertions, 4 deletions
diff --git a/CHANGES b/CHANGES
index a7457e6d3..00cb3384e 100644
--- a/CHANGES
+++ b/CHANGES
@@ -34,6 +34,10 @@ CHANGES
- session.merge() works with relations that specifically
don't include "merge" in their cascade options - the target
is ignored completely.
+
+ - fixed internal error which would occur if calling has()
+ or similar complex expression on a single-table inheritance
+ relation(). [ticket:1731]
- query.one() no longer applies LIMIT to the query, this to
ensure that it fully counts all object identities present
@@ -184,6 +188,10 @@ CHANGES
coercing a returned floating point value into a string
on its way to Decimal - this allows accuracy to function
on SQLite, MySQL. [ticket:1717]
+
+ - the copy() method of Column now copies over uninitialized
+ "on table attach" events. Helps with the new declarative
+ "mixin" capability.
- engines
- Added an optional C extension to speed up the sql layer by
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index 08386059d..8ffb68a4e 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -813,7 +813,7 @@ class Column(SchemaItem, expression.ColumnClause):
[c.copy(**kw) for c in self.constraints] + \
[c.copy(**kw) for c in self.foreign_keys if not c.constraint]
- return Column(
+ c = Column(
name=self.name,
type_=self.type,
key = self.key,
@@ -828,7 +828,10 @@ class Column(SchemaItem, expression.ColumnClause):
server_onupdate=self.server_onupdate,
*args
)
-
+ if hasattr(self, '_table_events'):
+ c._table_events = list(self._table_events)
+ return c
+
def _make_proxy(self, selectable, name=None):
"""Create a *proxy* for this column.
diff --git a/lib/sqlalchemy/sql/util.py b/lib/sqlalchemy/sql/util.py
index 43673eaec..1b90a457f 100644
--- a/lib/sqlalchemy/sql/util.py
+++ b/lib/sqlalchemy/sql/util.py
@@ -276,7 +276,9 @@ def _deep_annotate(element, annotations, exclude=None):
def clone(elem):
# check if element is present in the exclude list.
# take into account proxying relationships.
- if exclude and elem.proxy_set.intersection(exclude):
+ if exclude and \
+ hasattr(elem, 'proxy_set') and \
+ elem.proxy_set.intersection(exclude):
elem = elem._clone()
elif annotations != elem._annotations:
elem = elem._annotate(annotations.copy())
diff --git a/test/engine/test_metadata.py b/test/engine/test_metadata.py
index 0d2cb7775..3a1a19cd4 100644
--- a/test/engine/test_metadata.py
+++ b/test/engine/test_metadata.py
@@ -54,7 +54,20 @@ class MetaDataTest(TestBase, ComparesTables):
for a1, a2 in zip(col.foreign_keys, c2.foreign_keys):
assert a1 is not a2
eq_(a2._colspec, 'bat.blah')
-
+
+ def test_uninitialized_column_copy_events(self):
+ msgs = []
+ def write(t, c):
+ msgs.append("attach %s.%s" % (t.name, c.name))
+ c1 = Column('foo', String())
+ c1._on_table_attach(write)
+ m = MetaData()
+ for i in xrange(3):
+ cx = c1.copy()
+ t = Table('foo%d' % i, m, cx)
+ eq_(msgs, ['attach foo0.foo', 'attach foo1.foo', 'attach foo2.foo'])
+
+
def test_dupe_tables(self):
metadata = MetaData()
t1 = Table('table1', metadata, Column('col1', Integer, primary_key=True),
diff --git a/test/sql/test_generative.py b/test/sql/test_generative.py
index c31a24b93..a6f8c5956 100644
--- a/test/sql/test_generative.py
+++ b/test/sql/test_generative.py
@@ -286,6 +286,11 @@ class ClauseTest(TestBase, AssertsCompiledSQL):
assert u2.compile().params == {'id_param':7}
assert u3.compile().params == {'id_param':10}
+ def test_in(self):
+ expr = t1.c.col1.in_(['foo', 'bar'])
+ expr2 = CloningVisitor().traverse(expr)
+ assert str(expr) == str(expr2)
+
def test_adapt_union(self):
u = union(t1.select().where(t1.c.col1==4), t1.select().where(t1.c.col1==5)).alias()
diff --git a/test/sql/test_selectable.py b/test/sql/test_selectable.py
index f5f61aab1..78455e6d6 100644
--- a/test/sql/test_selectable.py
+++ b/test/sql/test_selectable.py
@@ -549,6 +549,20 @@ class AnnotationsTest(TestBase):
b5 = visitors.cloned_traverse(b3, {}, {'binary':visit_binary})
assert str(b5) == ":bar = table1.col2"
+ def test_annotate_expressions(self):
+ table1 = table('table1', column("col1"), column("col2"))
+
+ for expr, expected in [
+ (table1.c.col1, "table1.col1"),
+ (table1.c.col1 == 5, "table1.col1 = :col1_1"),
+ (table1.c.col1.in_([2,3,4]), "table1.col1 IN (:col1_1, :col1_2, :col1_3)")
+ ]:
+ eq_(str(expr), expected)
+ eq_(str(expr._annotate({})), expected)
+ eq_(str(sql_util._deep_annotate(expr, {})), expected)
+ eq_(str(sql_util._deep_annotate(expr, {}, exclude=[table1.c.col1])), expected)
+
+
def test_deannotate(self):
table1 = table('table1', column("col1"), column("col2"))