summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/schema.py
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/schema.py')
-rw-r--r--lib/sqlalchemy/schema.py144
1 files changed, 77 insertions, 67 deletions
diff --git a/lib/sqlalchemy/schema.py b/lib/sqlalchemy/schema.py
index 9a4bf4109..1f0b52ace 100644
--- a/lib/sqlalchemy/schema.py
+++ b/lib/sqlalchemy/schema.py
@@ -27,7 +27,7 @@ are part of the SQL expression language, they are usable as components in SQL
expressions. """
import re, inspect
-from sqlalchemy import types, exceptions, util, databases
+from sqlalchemy import types, exc, util, databases
from sqlalchemy.sql import expression, visitors
URL = None
@@ -42,10 +42,11 @@ class SchemaItem(object):
"""Base class for items that define a database schema."""
__metaclass__ = expression._FigureVisitName
-
+ quote = None
+
def _init_items(self, *args):
"""Initialize the list of child items for this SchemaItem."""
-
+
for item in args:
if item is not None:
item._set_parent(self)
@@ -95,7 +96,7 @@ class _TableSingleton(expression._FigureVisitName):
try:
table = metadata.tables[key]
if not useexisting and table._cant_override(*args, **kwargs):
- raise exceptions.InvalidRequestError(
+ raise exc.InvalidRequestError(
"Table '%s' is already defined for this MetaData instance. "
"Specify 'useexisting=True' to redefine options and "
"columns on an existing Table object." % key)
@@ -104,7 +105,7 @@ class _TableSingleton(expression._FigureVisitName):
return table
except KeyError:
if mustexist:
- raise exceptions.InvalidRequestError(
+ raise exc.InvalidRequestError(
"Table '%s' not defined" % (key))
try:
return type.__call__(self, name, metadata, *args, **kwargs)
@@ -182,17 +183,19 @@ class Table(SchemaItem, expression.TableClause):
Deprecated; this is an oracle-only argument - "schema" should
be used in its place.
- quote
- When True, indicates that the Table identifier must be quoted.
- This flag does *not* disable quoting; for case-insensitive names,
- use an all lower case identifier.
+ quote
+ Force quoting of the identifier on or off, based on `True` or
+ `False`. Defaults to `None`. This flag is rarely needed,
+ as quoting is normally applied
+ automatically for known reserved words, as well as for
+ "case sensitive" identifiers. An identifier is "case sensitive"
+ if it contains non-lowercase letters, otherwise it's
+ considered to be "case insensitive".
quote_schema
- When True, indicates that the schema identifier must be quoted.
- This flag does *not* disable quoting; for case-insensitive names,
- use an all lower case identifier.
+ same as 'quote' but applies to the schema identifier.
+
"""
-
super(Table, self).__init__(name)
self.metadata = metadata
self.schema = kwargs.pop('schema', kwargs.pop('owner', None))
@@ -214,7 +217,7 @@ class Table(SchemaItem, expression.TableClause):
self._set_parent(metadata)
- self.__extra_kwargs(**kwargs)
+ self.__extra_kwargs(**kwargs)
# load column definitions from the database if 'autoload' is defined
# we do it after the table is in the singleton dictionary to support
@@ -234,7 +237,7 @@ class Table(SchemaItem, expression.TableClause):
autoload_with = kwargs.pop('autoload_with', None)
schema = kwargs.pop('schema', None)
if schema and schema != self.schema:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Can't change schema of existing table from '%s' to '%s'",
(self.schema, schema))
@@ -258,8 +261,8 @@ class Table(SchemaItem, expression.TableClause):
['autoload', 'autoload_with', 'schema', 'owner']))
def __extra_kwargs(self, **kwargs):
- self.quote = kwargs.pop('quote', False)
- self.quote_schema = kwargs.pop('quote_schema', False)
+ self.quote = kwargs.pop('quote', None)
+ self.quote_schema = kwargs.pop('quote_schema', None)
if kwargs.get('info'):
self._info = kwargs.pop('info')
@@ -488,9 +491,13 @@ class Column(SchemaItem, expression._ColumnClause):
or subtype of Integer.
quote
- When True, indicates that the Column identifier must be quoted.
- This flag does *not* disable quoting; for case-insensitive names,
- use an all lower case identifier.
+ Force quoting of the identifier on or off, based on `True` or
+ `False`. Defaults to `None`. This flag is rarely needed,
+ as quoting is normally applied
+ automatically for known reserved words, as well as for
+ "case sensitive" identifiers. An identifier is "case sensitive"
+ if it contains non-lowercase letters, otherwise it's
+ considered to be "case insensitive".
"""
name = kwargs.pop('name', None)
@@ -499,7 +506,7 @@ class Column(SchemaItem, expression._ColumnClause):
args = list(args)
if isinstance(args[0], basestring):
if name is not None:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"May not pass name positionally and as a keyword.")
name = args.pop(0)
if args:
@@ -507,7 +514,7 @@ class Column(SchemaItem, expression._ColumnClause):
(isinstance(args[0], type) and
issubclass(args[0], types.AbstractType))):
if type_ is not None:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"May not pass type_ positionally and as a keyword.")
type_ = args.pop(0)
@@ -520,15 +527,17 @@ class Column(SchemaItem, expression._ColumnClause):
self.default = kwargs.pop('default', None)
self.index = kwargs.pop('index', None)
self.unique = kwargs.pop('unique', None)
- self.quote = kwargs.pop('quote', False)
+ self.quote = kwargs.pop('quote', None)
self.onupdate = kwargs.pop('onupdate', None)
self.autoincrement = kwargs.pop('autoincrement', True)
self.constraints = util.Set()
self.foreign_keys = util.OrderedSet()
+ util.set_creation_order(self)
+
if kwargs.get('info'):
self._info = kwargs.pop('info')
if kwargs:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Unknown arguments passed to Column: " + repr(kwargs.keys()))
def __str__(self):
@@ -545,7 +554,7 @@ class Column(SchemaItem, expression._ColumnClause):
bind = property(bind)
def references(self, column):
- """Return True if this references the given column via a foreign key."""
+ """Return True if this Column references the given column via foreign key."""
for fk in self.foreign_keys:
if fk.references(column.table):
return True
@@ -576,14 +585,14 @@ class Column(SchemaItem, expression._ColumnClause):
def _set_parent(self, table):
if self.name is None:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Column must be constructed with a name or assign .name "
"before adding to a Table.")
if self.key is None:
self.key = self.name
self.metadata = table.metadata
if getattr(self, 'table', None) is not None:
- raise exceptions.ArgumentError("this Column already has a table!")
+ raise exc.ArgumentError("this Column already has a table!")
if not self._is_oid:
self._pre_existing_column = table._columns.get(self.key)
@@ -594,7 +603,7 @@ class Column(SchemaItem, expression._ColumnClause):
if self.primary_key:
table.primary_key.replace(self)
elif self.key in table.primary_key:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Trying to redefine primary-key column '%s' as a "
"non-primary-key column on table '%s'" % (
self.key, table.fullname))
@@ -604,14 +613,14 @@ class Column(SchemaItem, expression._ColumnClause):
if self.index:
if isinstance(self.index, basestring):
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"The 'index' keyword argument on Column is boolean only. "
"To create indexes with a specific name, create an "
"explicit Index object external to the Table.")
Index('ix_%s' % self._label, self, unique=self.unique)
elif self.unique:
if isinstance(self.unique, basestring):
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"The 'unique' keyword argument on Column is boolean only. "
"To create unique constraints or indexes with a specific "
"name, append an explicit UniqueConstraint to the Table's "
@@ -631,17 +640,17 @@ class Column(SchemaItem, expression._ColumnClause):
"""Create a copy of this ``Column``, unitialized.
This is used in ``Table.tometadata``.
- """
+ """
return Column(self.name, self.type, self.default, key = self.key, primary_key = self.primary_key, nullable = self.nullable, _is_oid = self._is_oid, quote=self.quote, index=self.index, autoincrement=self.autoincrement, *[c.copy() for c in self.constraints])
-
- def _make_proxy(self, selectable, name = None):
+
+ def _make_proxy(self, selectable, name=None):
"""Create a *proxy* for this column.
This is a copy of this ``Column`` referenced by a different parent
(such as an alias or select statement).
- """
+ """
fk = [ForeignKey(f._colspec) for f in self.foreign_keys]
c = Column(name or self.name, self.type, self.default, key = name or self.key, primary_key = self.primary_key, nullable = self.nullable, _is_oid = self._is_oid, quote=self.quote, *fk)
c.table = selectable
@@ -654,7 +663,6 @@ class Column(SchemaItem, expression._ColumnClause):
[c._init_items(f) for f in fk]
return c
-
def get_children(self, schema_visitor=False, **kwargs):
if schema_visitor:
return [x for x in (self.default, self.onupdate) if x is not None] + \
@@ -670,8 +678,8 @@ class ForeignKey(SchemaItem):
For a composite (multiple column) FOREIGN KEY, use a ForeignKeyConstraint
within the Table definition.
- """
+ """
def __init__(self, column, constraint=None, use_alter=False, name=None, onupdate=None, ondelete=None, deferrable=None, initially=None):
"""Construct a column-level FOREIGN KEY.
@@ -742,14 +750,15 @@ class ForeignKey(SchemaItem):
def references(self, table):
"""Return True if the given table is referenced by this ForeignKey."""
-
return table.corresponding_column(self.column) is not None
def get_referent(self, table):
"""Return the column in the given table referenced by this ForeignKey.
Returns None if this ``ForeignKey`` does not reference the given table.
+
"""
+
return table.corresponding_column(self.column)
def column(self):
@@ -766,22 +775,22 @@ class ForeignKey(SchemaItem):
parenttable = c.table
break
else:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Parent column '%s' does not descend from a "
"table-attached Column" % str(self.parent))
m = re.match(r"^(.+?)(?:\.(.+?))?(?:\.(.+?))?$", self._colspec,
re.UNICODE)
if m is None:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Invalid foreign key column specification: %s" %
self._colspec)
if m.group(3) is None:
(tname, colname) = m.group(1, 2)
schema = None
else:
- (schema,tname,colname) = m.group(1,2,3)
+ (schema, tname, colname) = m.group(1, 2, 3)
if _get_table_key(tname, schema) not in parenttable.metadata:
- raise exceptions.NoReferencedTableError(
+ raise exc.NoReferencedTableError(
"Could not find table '%s' with which to generate a "
"foreign key" % tname)
table = Table(tname, parenttable.metadata,
@@ -797,13 +806,13 @@ class ForeignKey(SchemaItem):
else:
self._column = table.c[colname]
except KeyError, e:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Could not create ForeignKey '%s' on table '%s': "
"table '%s' has no column named '%s'" % (
self._colspec, parenttable.name, table.name, str(e)))
-
- elif isinstance(self._colspec, expression.Operators):
- self._column = self._colspec.clause_element()
+
+ elif hasattr(self._colspec, '__clause_element__'):
+ self._column = self._colspec.__clause_element__()
else:
self._column = self._colspec
@@ -906,12 +915,11 @@ class ColumnDefault(DefaultGenerator):
defaulted = argspec[3] is not None and len(argspec[3]) or 0
if positionals - defaulted > 1:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"ColumnDefault Python function takes zero or one "
"positional arguments")
return fn
-
def _visit_name(self):
if self.for_update:
return "column_onupdate"
@@ -926,12 +934,12 @@ class Sequence(DefaultGenerator):
"""Represents a named database sequence."""
def __init__(self, name, start=None, increment=None, schema=None,
- optional=False, quote=False, **kwargs):
+ optional=False, quote=None, **kwargs):
super(Sequence, self).__init__(**kwargs)
self.name = name
self.start = start
self.increment = increment
- self.optional=optional
+ self.optional = optional
self.quote = quote
self.schema = schema
self.kwargs = kwargs
@@ -960,7 +968,6 @@ class Sequence(DefaultGenerator):
bind = _bind_or_error(self)
bind.drop(self, checkfirst=checkfirst)
-
class Constraint(SchemaItem):
"""A table-level SQL constraint, such as a KEY.
@@ -989,8 +996,11 @@ class Constraint(SchemaItem):
self.initially = initially
def __contains__(self, x):
- return self.columns.contains_column(x)
-
+ return x in self.columns
+
+ def contains_column(self, col):
+ return self.columns.contains_column(col)
+
def keys(self):
return self.columns.keys()
@@ -1105,7 +1115,7 @@ class ForeignKeyConstraint(Constraint):
self.onupdate = onupdate
self.ondelete = ondelete
if self.name is None and use_alter:
- raise exceptions.ArgumentError("Alterable ForeignKey/ForeignKeyConstraint requires a name")
+ raise exc.ArgumentError("Alterable ForeignKey/ForeignKeyConstraint requires a name")
self.use_alter = use_alter
def _set_parent(self, table):
@@ -1113,7 +1123,7 @@ class ForeignKeyConstraint(Constraint):
if self not in table.constraints:
table.constraints.add(self)
for (c, r) in zip(self.__colnames, self.__refcolnames):
- self.append_element(c,r)
+ self.append_element(c, r)
def append_element(self, col, refcol):
fk = ForeignKey(refcol, constraint=self, name=self.name, onupdate=self.onupdate, ondelete=self.ondelete, use_alter=self.use_alter)
@@ -1159,7 +1169,7 @@ class PrimaryKeyConstraint(Constraint):
deferrable=kwargs.pop('deferrable', None),
initially=kwargs.pop('initially', None))
if kwargs:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
'Unknown PrimaryKeyConstraint argument(s): %s' %
', '.join([repr(x) for x in kwargs.keys()]))
@@ -1174,14 +1184,14 @@ class PrimaryKeyConstraint(Constraint):
def add(self, col):
self.columns.add(col)
- col.primary_key=True
+ col.primary_key = True
append_column = add
def replace(self, col):
self.columns.replace(col)
def remove(self, col):
- col.primary_key=False
+ col.primary_key = False
del self.columns[col.key]
def copy(self):
@@ -1222,7 +1232,7 @@ class UniqueConstraint(Constraint):
deferrable=kwargs.pop('deferrable', None),
initially=kwargs.pop('initially', None))
if kwargs:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
'Unknown UniqueConstraint argument(s): %s' %
', '.join([repr(x) for x in kwargs.keys()]))
@@ -1295,11 +1305,11 @@ class Index(SchemaItem):
self._set_parent(column.table)
elif column.table != self.table:
# all columns muse be from same table
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"All index columns must be from same table. "
"%s is from %s not %s" % (column, column.table, self.table))
elif column.name in [ c.name for c in self.columns ]:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"A column may not appear twice in the "
"same index (%s already has column %s)" % (self.name, column))
self.columns.append(column)
@@ -1370,7 +1380,7 @@ class MetaData(SchemaItem):
self.ddl_listeners = util.defaultdict(list)
if reflect:
if not bind:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"A bind must be supplied in conjunction with reflect=True")
self.reflect()
@@ -1508,7 +1518,7 @@ class MetaData(SchemaItem):
missing = [name for name in only if name not in available]
if missing:
s = schema and (" schema '%s'" % schema) or ''
- raise exceptions.InvalidRequestError(
+ raise exc.InvalidRequestError(
'Could not reflect: requested table(s) not available '
'in %s%s: (%s)' % (bind.engine.url, s, ', '.join(missing)))
load = [name for name in only if name not in current]
@@ -1777,12 +1787,12 @@ class DDL(object):
"""
if not isinstance(statement, basestring):
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Expected a string or unicode SQL statement, got '%r'" %
statement)
if (on is not None and
(not isinstance(on, basestring) and not callable(on))):
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Expected the name of a database dialect or a callable for "
"'on' criteria, got type '%s'." % type(on).__name__)
@@ -1858,10 +1868,10 @@ class DDL(object):
"""
if not hasattr(schema_item, 'ddl_listeners'):
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"%s does not support DDL events" % type(schema_item).__name__)
if event not in schema_item.ddl_events:
- raise exceptions.ArgumentError(
+ raise exc.ArgumentError(
"Unknown event, expected one of (%s), got '%r'" %
(', '.join(schema_item.ddl_events), event))
schema_item.ddl_listeners[event].append(self)
@@ -1955,5 +1965,5 @@ def _bind_or_error(schemaitem):
'Execution can not proceed without a database to execute '
'against. Either execute with an explicit connection or '
'assign %s to enable implicit execution.') % (item, bindable)
- raise exceptions.UnboundExecutionError(msg)
+ raise exc.UnboundExecutionError(msg)
return bind