From f979c19841e6803099827d58d4de65964391be49 Mon Sep 17 00:00:00 2001 From: Jason Kirtland Date: Tue, 18 Mar 2008 00:15:34 +0000 Subject: [PATCH] - 'name' is no longer a require constructor argument for Column(). It (and .key) may now be deferred until the Column is added to a Table. --- CHANGES | 5 +++++ lib/sqlalchemy/schema.py | 24 +++++++++++++++++++- test/sql/alltests.py | 1 + test/sql/columns.py | 48 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 test/sql/columns.py diff --git a/CHANGES b/CHANGES index 695c730353..b31a9dac24 100644 --- a/CHANGES +++ b/CHANGES @@ -24,6 +24,11 @@ CHANGES had only been implemented for foreign-key nulling behavior in 0.4.2 and not actual cascading deletes [ticket:895] +- sql + - 'name' is no longer a required constructor argument for + Column(). It (and .key) may now be deferred until the column + is added to a Table. + - extensions - The "synonym" function is now directly usable with "declarative". Pass in the decorated property using the diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py index 8d0b3d26d2..c3db8bfad3 100644 --- a/lib/sqlalchemy/schema.py +++ b/lib/sqlalchemy/schema.py @@ -405,7 +405,7 @@ class Column(SchemaItem, expression._ColumnClause): ``TableClause``/``Table``. """ - def __init__(self, name, type_, *args, **kwargs): + def __init__(self, *args, **kwargs): """Construct a new ``Column`` object. Arguments are: @@ -497,6 +497,24 @@ class Column(SchemaItem, expression._ColumnClause): auto-detect conditions where quoting is required. """ + name = kwargs.pop('name', None) + type_ = kwargs.pop('type_', None) + if args: + args = list(args) + if isinstance(args[0], basestring): + if name is not None: + raise exceptions.ArgumentError( + "May not pass name positionally and as a keyword.") + name = args.pop(0) + if args: + if (isinstance(args[0], types.AbstractType) or + (isinstance(args[0], type) and + issubclass(args[0], types.AbstractType))): + if type_ is not None: + raise exceptions.ArgumentError( + "May not pass type_ positionally and as a keyword.") + type_ = args.pop(0) + super(Column, self).__init__(name, None, type_) self.args = args self.key = kwargs.pop('key', name) @@ -561,6 +579,10 @@ class Column(SchemaItem, expression._ColumnClause): ["%s=%s" % (k, repr(getattr(self, k))) for k in kwarg]) def _set_parent(self, table): + if self.name is None: + raise exceptions.ArgumentError( + "Column must be constructed with a name or assign .name " + "before adding to a Table.") self.metadata = table.metadata if getattr(self, 'table', None) is not None: raise exceptions.ArgumentError("this Column already has a table!") diff --git a/test/sql/alltests.py b/test/sql/alltests.py index f49cf14d4b..173b046327 100644 --- a/test/sql/alltests.py +++ b/test/sql/alltests.py @@ -5,6 +5,7 @@ import unittest def suite(): modules_to_test = ( 'sql.testtypes', + 'sql.columns', 'sql.constraints', 'sql.generative', diff --git a/test/sql/columns.py b/test/sql/columns.py new file mode 100644 index 0000000000..0a904bee14 --- /dev/null +++ b/test/sql/columns.py @@ -0,0 +1,48 @@ +import testenv; testenv.configure_for_tests() +from sqlalchemy import * +from sqlalchemy import exceptions, sql +from testlib import * +from sqlalchemy import Table, Column # don't use testlib's wrappers + + +class ColumnDefinitionTest(TestBase): + """Test Column() construction.""" + + # flesh this out with explicit coverage... + + def columns(self): + return [ Column(), + Column('b'), + Column(Integer), + Column('d', Integer), + Column(name='e'), + Column(type_=Integer), + Column(Integer()), + Column('h', Integer()), + Column(type_=Integer()) ] + + def test_basic(self): + c = self.columns() + + for i, v in ((0, 'a'), (2, 'c'), (5, 'f'), (6, 'g'), (8, 'i')): + c[i].name = v + c[i].key = v + del i, v + + tbl = Table('table', MetaData(), *c) + + for i, col in enumerate(tbl.c): + assert col.name == c[i].name + + def test_incomplete(self): + c = self.columns() + + self.assertRaises(exceptions.ArgumentError, Table, 't', MetaData(), *c) + + def test_bogus(self): + self.assertRaises(exceptions.ArgumentError, Column, 'foo', name='bar') + self.assertRaises(exceptions.ArgumentError, Column, 'foo', Integer, + type_=Integer()) + +if __name__ == "__main__": + testenv.main() -- 2.47.3