From: Mike Bayer Date: Mon, 28 Feb 2011 17:47:04 +0000 (-0500) Subject: - Added a fully descriptive error message for the X-Git-Tag: rel_0_7b3~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cf5113115047032dd46724d1e3f56dfca6503eee;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git - Added a fully descriptive error message for the case where Column is subclassed and _make_proxy() fails to make a copy due to TypeError on the constructor. The method _constructor should be implemented in this case. --- diff --git a/CHANGES b/CHANGES index 25c955ec25..b6b6b3bf8e 100644 --- a/CHANGES +++ b/CHANGES @@ -3,6 +3,15 @@ ======= CHANGES ======= +0.7.0b3 +======= +- sql + - Added a fully descriptive error message for the + case where Column is subclassed and _make_proxy() + fails to make a copy due to TypeError on the + constructor. The method _constructor should + be implemented in this case. + 0.7.0b2 ======== - orm diff --git a/lib/sqlalchemy/__init__.py b/lib/sqlalchemy/__init__.py index a3c0c32388..2b4cfde0fc 100644 --- a/lib/sqlalchemy/__init__.py +++ b/lib/sqlalchemy/__init__.py @@ -116,6 +116,6 @@ from sqlalchemy.engine import create_engine, engine_from_config __all__ = sorted(name for name, obj in locals().items() if not (name.startswith('_') or inspect.ismodule(obj))) -__version__ = '0.7b2' +__version__ = '0.7b3' del inspect, sys diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 80d6018b84..223643c804 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -904,13 +904,32 @@ class Column(SchemaItem, expression.ColumnClause): raise exc.InvalidRequestError("Cannot initialize a sub-selectable" " with this Column object until it's 'name' has " "been assigned.") - c = self._constructor( - name or self.name, - self.type, - key = name or self.key, - primary_key = self.primary_key, - nullable = self.nullable, - quote=self.quote, _proxies=[self], *fk) + try: + c = self._constructor( + name or self.name, + self.type, + key = name or self.key, + primary_key = self.primary_key, + nullable = self.nullable, + quote=self.quote, _proxies=[self], *fk) + except TypeError, e: + # Py3K + #raise TypeError( + # "Could not create a copy of this %r object. " + # "Ensure the class includes a _constructor() " + # "attribute or method which accepts the " + # "standard Column constructor arguments, or " + # "references the Column class itself." % self.__class__) from e + # Py2K + raise TypeError( + "Could not create a copy of this %r object. " + "Ensure the class includes a _constructor() " + "attribute or method which accepts the " + "standard Column constructor arguments, or " + "references the Column class itself. " + "Original error: %s" % (self.__class__, e)) + # end Py2K + c.table = selectable selectable._columns.add(c) if self.primary_key: diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index ace3b69d5a..4c0abd1f0f 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -547,10 +547,10 @@ class ConstraintTest(TestBase): assert s1.c.a.references(t1.c.a) assert not s1.c.a.references(t1.c.b) -class ColumnDefinitionTest(TestBase): +class ColumnDefinitionTest(AssertsCompiledSQL, TestBase): """Test Column() construction.""" - # flesh this out with explicit coverage... + __dialect__ = 'default' def columns(self): return [ Column(Integer), @@ -598,6 +598,78 @@ class ColumnDefinitionTest(TestBase): assert_raises(exc.ArgumentError, Column, 'foo', Integer, type_=Integer()) + def test_custom_subclass_proxy(self): + """test proxy generation of a Column subclass, can be compiled.""" + + from sqlalchemy.schema import Column + from sqlalchemy.ext.compiler import compiles + from sqlalchemy.sql import select + + class MyColumn(Column): + def _constructor(self, name, type, **kw): + kw['name'] = name + return MyColumn(type, **kw) + + def __init__(self, type, **kw): + Column.__init__(self, type, **kw) + + def my_goofy_thing(self): + return "hi" + + @compiles(MyColumn) + def goofy(element, compiler, **kw): + s = compiler.visit_column(element, **kw) + return s + "-" + + id = MyColumn(Integer, primary_key=True) + id.name = 'id' + name = MyColumn(String) + name.name = 'name' + t1 = Table('foo', MetaData(), + id, + name + ) + + # goofy thing + eq_(t1.c.name.my_goofy_thing(), "hi") + + # create proxy + s = select([t1.select().alias()]) + + # proxy has goofy thing + eq_(s.c.name.my_goofy_thing(), "hi") + + # compile works + self.assert_compile( + select([t1.select().alias()]), + "SELECT anon_1.id-, anon_1.name- FROM " + "(SELECT foo.id- AS id, foo.name- AS name " + "FROM foo) AS anon_1", + ) + + def test_custom_subclass_proxy_typeerror(self): + from sqlalchemy.schema import Column + from sqlalchemy.sql import select + + class MyColumn(Column): + def __init__(self, type, **kw): + Column.__init__(self, type, **kw) + + id = MyColumn(Integer, primary_key=True) + id.name = 'id' + name = MyColumn(String) + name.name = 'name' + t1 = Table('foo', MetaData(), + id, + name + ) + assert_raises_message( + TypeError, + "Could not create a copy of this " + "object. Ensure the class includes a _constructor()", + getattr, select([t1.select().alias()]), 'c' + ) class ColumnOptionsTest(TestBase):