Commits

Mike Bayer  committed e8e142c

the @memoized_property fairy pays a visit

  • Participants
  • Parent commits ac82843

Comments (0)

Files changed (2)

File lib/sqlalchemy/schema.py

         """
 
         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
+        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
+                    _column = table.c[self.parent.key]
                 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)))
+                    _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__()
-            else:
-                self._column = self._colspec
+        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

File lib/sqlalchemy/sql/expression.py

         """
         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():