"""
self._colspec = column
- self._column = None
self.constraint = constraint
self.use_alter = use_alter
self.name = name
return table.corresponding_column(self.column)
+ @util.memoized_property
def column(self):
# ForeignKey inits its remote column as late as possible, so tables
# can be defined without dependencies
- if self._column is None:
- if isinstance(self._colspec, basestring):
- # locate the parent table this foreign key is attached to. we
- # use the "original" column which our parent column represents
- # (its a list of columns/other ColumnElements if the parent
- # table is a UNION)
- for c in self.parent.base_columns:
- if isinstance(c, Column):
- parenttable = c.table
- break
- else:
- 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 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)
- if _get_table_key(tname, schema) not in parenttable.metadata:
- raise exc.NoReferencedTableError(
- "Could not find table '%s' with which to generate a "
- "foreign key" % tname)
- table = Table(tname, parenttable.metadata,
- mustexist=True, schema=schema)
- try:
- if colname is None:
- # colname is None in the case that ForeignKey argument
- # was specified as table name only, in which case we
- # match the column name to the same column on the
- # parent.
- key = self.parent
- self._column = table.c[self.parent.key]
- else:
- self._column = table.c[colname]
- except KeyError, e:
- raise exc.NoReferencedColumnError(
- "Could not create ForeignKey '%s' on table '%s': "
- "table '%s' has no column named '%s'" % (
- self._colspec, parenttable.name, table.name, str(e)))
-
- elif hasattr(self._colspec, '__clause_element__'):
- self._column = self._colspec.__clause_element__()
+ if isinstance(self._colspec, basestring):
+ # locate the parent table this foreign key is attached to. we
+ # use the "original" column which our parent column represents
+ # (its a list of columns/other ColumnElements if the parent
+ # table is a UNION)
+ for c in self.parent.base_columns:
+ if isinstance(c, Column):
+ parenttable = c.table
+ break
else:
- self._column = self._colspec
+ 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 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)
+ if _get_table_key(tname, schema) not in parenttable.metadata:
+ raise exc.NoReferencedTableError(
+ "Could not find table '%s' with which to generate a "
+ "foreign key" % tname)
+ table = Table(tname, parenttable.metadata,
+ mustexist=True, schema=schema)
+ try:
+ if colname is None:
+ # colname is None in the case that ForeignKey argument
+ # was specified as table name only, in which case we
+ # match the column name to the same column on the
+ # parent.
+ key = self.parent
+ _column = table.c[self.parent.key]
+ else:
+ _column = table.c[colname]
+ except KeyError, e:
+ raise exc.NoReferencedColumnError(
+ "Could not create ForeignKey '%s' on table '%s': "
+ "table '%s' has no column named '%s'" % (
+ self._colspec, parenttable.name, table.name, str(e)))
+
+ elif hasattr(self._colspec, '__clause_element__'):
+ _column = self._colspec.__clause_element__()
+ else:
+ _column = self._colspec
# propagate TypeEngine to parent if it didn't have one
if isinstance(self.parent.type, types.NullType):
- self.parent.type = self._column.type
- return self._column
-
- column = property(column)
+ self.parent.type = _column.type
+ return _column
def _set_parent(self, column):
self.parent = column
"""
c = self.__class__.__new__(self.__class__)
c.__dict__ = self.__dict__.copy()
+ c.__dict__.pop('_cloned_set', None)
# this is a marker that helps to "equate" clauses to each other
# when a Select returns its list of FROM clauses. the cloning
return c
- @property
+ @util.memoized_property
def _cloned_set(self):
"""Return the set consisting all cloned anscestors of this ClauseElement.
of transformative operations.
"""
+ s = set()
f = self
while f is not None:
- yield f
+ s.add(f)
f = getattr(f, '_is_clone_of', None)
-
+ return s
+
def __getstate__(self):
d = self.__dict__.copy()
d.pop('_is_clone_of', None)
def _select_iterable(self):
return (self, )
- @property
+ @util.memoized_property
def base_columns(self):
- if not hasattr(self, '_base_columns'):
- self._base_columns = set(c for c in self.proxy_set
+ return set(c for c in self.proxy_set
if not hasattr(c, 'proxies'))
- return self._base_columns
- @property
+ @util.memoized_property
def proxy_set(self):
- if not hasattr(self, '_proxy_set'):
- s = set([self])
- if hasattr(self, 'proxies'):
- for c in self.proxies:
- s.update(c.proxy_set)
- self._proxy_set = s
- return self._proxy_set
-
+ s = set([self])
+ if hasattr(self, 'proxies'):
+ for c in self.proxies:
+ s.update(c.proxy_set)
+ return s
+
def shares_lineage(self, othercolumn):
"""Return True if the given ``ColumnElement`` has a common ancestor to this ``ColumnElement``."""
An example would be an Alias of a Table is derived from that Table.
"""
- return fromclause in set(self._cloned_set)
+ return fromclause in self._cloned_set
def replace_selectable(self, old, alias):
"""replace all occurences of FromClause 'old' with the given Alias object, returning a copy of this ``FromClause``."""
return self.name.encode('ascii', 'backslashreplace')
def is_derived_from(self, fromclause):
- if fromclause in set(self._cloned_set):
+ if fromclause in self._cloned_set:
return True
return self.element.is_derived_from(fromclause)
@property
def _label(self):
- try:
- return self.element._label
- except AttributeError:
- return self.anon_label
+ return getattr(self.element, '_label', None) or self.anon_label
def _copy_internals(self, clone=_clone):
self.element = clone(self.element)
return itertools.chain(*[c._select_iterable for c in self._raw_columns])
def is_derived_from(self, fromclause):
- if self in set(fromclause._cloned_set):
+ if self in fromclause._cloned_set:
return True
for f in self.locate_all_froms():