Commits

Anonymous committed 3efd245

- 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.

Comments (0)

Files changed (4)

 =======
 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

lib/sqlalchemy/__init__.py

 __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

lib/sqlalchemy/schema.py

             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:

test/sql/test_metadata.py

         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),
         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 <class "
+            "'test.sql.test_metadata.MyColumn'> "
+            "object.  Ensure the class includes a _constructor()",
+            getattr, select([t1.select().alias()]), 'c'
+        )
 
 class ColumnOptionsTest(TestBase):
 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.