Commits

Philip Jenvey  committed edd1ee5 Merge

merge default

  • Participants
  • Parent commits 2462443, e9f84aa

Comments (0)

Files changed (19)

     manager to Session, used with with:
     will temporarily disable autoflush.
 
+  - [feature] Added cte() method to Query,
+    invokes common table expression support
+    from the Core (see below). [ticket:1859]
+
   - [bug] Fixed bug whereby MappedCollection
     would not get the appropriate collection
     instrumentation if it were only used
     @collection.internally_instrumented.  
     [ticket:2406]
 
+  - [bug] Fixed bug whereby SQL adaption mechanics
+    would fail in a very nested scenario involving
+    joined-inheritance, joinedload(), limit(), and a
+    derived function in the columns clause.  
+    [ticket:2419]
+
+  - [bug] Fixed the repr() for CascadeOptions to
+    include refresh-expire.  Also reworked
+    CascadeOptions to be a <frozenset>.
+    [ticket:2417]
+
   - [feature] Added the ability to query for
     Table-bound column names when using 
     query(sometable).filter_by(colname=value).  
     on the method object.  [ticket:2352]
 
 - sql
+  - [feature] Added support for SQL standard
+    common table expressions (CTE), allowing
+    SELECT objects as the CTE source (DML
+    not yet supported).  This is invoked via
+    the cte() method on any select() construct.
+    [ticket:1859]
+
   - [bug] Added support for using the .key
     of a Column as a string identifier in a 
     result set row.   The .key is currently

File CHANGES_PRE_06

     - Added support for returning values from inserts (2.0+ only),
       updates and deletes (2.1+ only).
 
+0.4.9 (unreleased)
+==================
+
+- general:
+    - global "propigate"->"propagate" change.
+
+- orm
+    - polymorphic_union() function respects the "key" of each 
+      Column if they differ from the column's name.
+
+    - Fixed 0.4-only bug preventing composite columns
+      from working properly with inheriting mappers
+      [ticket:1199]
+
+    - Fixed RLock-related bug in mapper which could deadlock upon
+      reentrant mapper compile() calls, something that occurs when
+      using declarative constructs inside of ForeignKey objects.
+      Ported from 0.5.
+
+    - Fixed bug in composite types which prevented a primary-key
+      composite type from being mutated [ticket:1213].
+
+    - Added ScopedSession.is_active accessor. [ticket:976]
+
+    - Class-bound accessor can be used as the argument to 
+      relation() order_by.  [ticket:939]
+
+    - Fixed shard_id argument on ShardedSession.execute().
+      [ticket:1072]
+
+- sql
+    - Connection.invalidate() checks for closed status 
+      to avoid attribute errors. [ticket:1246]
+
+    - NullPool supports reconnect on failure behavior.
+      [ticket:1094]
+
+    - The per-dialect cache used by TypeEngine to cache
+      dialect-specific types is now a WeakKeyDictionary.
+      This to prevent dialect objects from 
+      being referenced forever for an application that 
+      creates an arbitrarily large number of engines
+      or dialects.   There is a small performance penalty
+      which will be resolved in 0.6.  [ticket:1299]
+
+-sqlite
+    - Fixed SQLite reflection methods so that non-present
+      cursor.description, which triggers an auto-cursor
+      close, will be detected so that no results doesn't
+      fail on recent versions of pysqlite which raise 
+      an error when fetchone() called with no rows present.
+
+- postgres
+    - Added Index reflection support to Postgres, using a
+      great patch we long neglected, submitted by 
+      Ken Kuhlman. [ticket:714]
+
+- mysql
+    - Fixed bug in exception raise when FK columns not present
+      during reflection. [ticket:1241]
+
+- oracle
+    - Fixed bug which was preventing out params of certain types
+      from being received; thanks a ton to huddlej at wwu.edu !
+      [ticket:1265]
+
+0.4.8
+=====
+- orm
+    - Fixed bug regarding inherit_condition passed
+      with "A=B" versus "B=A" leading to errors
+      [ticket:1039]
+
+    - Changes made to new, dirty and deleted 
+      collections in
+      SessionExtension.before_flush() will take
+      effect for that flush.
+
+    - Added label() method to InstrumentedAttribute 
+      to establish forwards compatibility with 0.5.
+
+- sql
+    - column.in_(someselect) can now be used as 
+      a columns-clause expression without the subquery
+      bleeding into the FROM clause [ticket:1074]
+
+- mysql
+    - Added MSMediumInteger type [ticket:1146].
+
+- sqlite
+    - Supplied a custom strftime() function which
+      handles dates before 1900.  [ticket:968]
+
+    - String's (and Unicode's, UnicodeText's, etc.) 
+      convert_unicode logic disabled in the sqlite dialect, 
+      to adjust for pysqlite 2.5.0's new requirement that 
+      only Python unicode objects are accepted;
+      http://itsystementwicklung.de/pipermail/list-pysqlite/2008-March/000018.html
+
+- oracle
+    - has_sequence() now takes schema name into account
+      [ticket:1155]
+    - added BFILE to the list of reflected types
+      [ticket:1121]
+
+0.4.7p1
+=====
+- orm 
+    - Added "add()" and "add_all()" to scoped_session
+      methods.  Workaround for 0.4.7:
+
+        from sqlalchemy.orm.scoping import ScopedSession,\
+        instrument
+        setattr(
+            ScopedSession, "add", instrument("add"))
+        setattr(
+            ScopedSession, "add_all", instrument("add_all"))
+
+    - Fixed non-2.3 compatible usage of set() and generator
+      expression within relation().
+
 0.4.7
 =====
 - orm

File doc/build/core/expression_api.rst

    :members:
    :show-inheritance:
 
+.. autoclass:: CTE
+   :members:
+   :show-inheritance:
+
 .. autoclass:: Delete
    :members: where
    :show-inheritance:

File lib/sqlalchemy/__init__.py

 __all__ = sorted(name for name, obj in locals().items()
                  if not (name.startswith('_') or inspect.ismodule(obj)))
 
-__version__ = '0.7.5'
+__version__ = '0.7.6'
 
 del inspect, sys
 

File lib/sqlalchemy/dialects/mssql/base.py

         ]
         return 'OUTPUT ' + ', '.join(columns)
 
+    def get_cte_preamble(self, recursive):
+        # SQL Server finds it too inconvenient to accept
+        # an entirely optional, SQL standard specified,
+        # "RECURSIVE" word with their "WITH",
+        # so here we go
+        return "WITH"
+
     def label_select_column(self, select, column, asfrom):
         if isinstance(column, expression.Function):
             return column.label(None)

File lib/sqlalchemy/orm/query.py

         """
         return self.enable_eagerloads(False).statement.alias(name=name)
 
+    def cte(self, name=None, recursive=False):
+        """Return the full SELECT statement represented by this :class:`.Query`
+        represented as a common table expression (CTE).
+
+        The :meth:`.Query.cte` method is new in 0.7.6.
+        
+        Parameters and usage are the same as those of the 
+        :meth:`._SelectBase.cte` method; see that method for 
+        further details.
+        
+        Here is the `Postgresql WITH 
+        RECURSIVE example <http://www.postgresql.org/docs/8.4/static/queries-with.html>`_.
+        Note that, in this example, the ``included_parts`` cte and the ``incl_alias`` alias
+        of it are Core selectables, which
+        means the columns are accessed via the ``.c.`` attribute.  The ``parts_alias``
+        object is an :func:`.orm.aliased` instance of the ``Part`` entity, so column-mapped
+        attributes are available directly::
+
+            from sqlalchemy.orm import aliased
+
+            class Part(Base):
+                __tablename__ = 'part'
+                part = Column(String, primary_key=True)
+                sub_part = Column(String, primary_key=True)
+                quantity = Column(Integer)
+
+            included_parts = session.query(
+                                Part.sub_part, 
+                                Part.part, 
+                                Part.quantity).\\
+                                    filter(Part.part=="our part").\\
+                                    cte(name="included_parts", recursive=True)
+
+            incl_alias = aliased(included_parts, name="pr")
+            parts_alias = aliased(Part, name="p")
+            included_parts = included_parts.union_all(
+                session.query(
+                    parts_alias.part, 
+                    parts_alias.sub_part, 
+                    parts_alias.quantity).\\
+                        filter(parts_alias.part==incl_alias.c.sub_part)
+                )
+
+            q = session.query(
+                    included_parts.c.sub_part,
+                    func.sum(included_parts.c.quantity).label('total_quantity')
+                ).\\
+                group_by(included_parts.c.sub_part)
+
+        See also:
+        
+        :meth:`._SelectBase.cte`
+
+        """
+        return self.enable_eagerloads(False).statement.cte(name=name, recursive=recursive)
+
     def label(self, name):
         """Return the full SELECT statement represented by this :class:`.Query`, converted 
         to a scalar subquery with a label of the given name.

File lib/sqlalchemy/orm/util.py

                                 PropComparator, MapperProperty
 from sqlalchemy.orm import attributes, exc
 import operator
+import re
 
 mapperlib = util.importlater("sqlalchemy.orm", "mapperlib")
 
 
 _INSTRUMENTOR = ('mapper', 'instrumentor')
 
-class CascadeOptions(dict):
+class CascadeOptions(frozenset):
     """Keeps track of the options sent to relationship().cascade"""
 
-    def __init__(self, arg=""):
-        if not arg:
-            values = set()
-        else:
-            values = set(c.strip() for c in arg.split(','))
+    _add_w_all_cascades = all_cascades.difference([
+                            'all', 'none', 'delete-orphan'])
+    _allowed_cascades = all_cascades
 
-        for name in ['save-update', 'delete', 'refresh-expire', 
-                            'merge', 'expunge']:
-            boolean = name in values or 'all' in values
-            setattr(self, name.replace('-', '_'), boolean)
-            if boolean:
-                self[name] = True
+    def __new__(cls, arg):
+        values = set([
+                    c for c 
+                    in re.split('\s*,\s*', arg or "")
+                    if c
+                ])
+
+        if values.difference(cls._allowed_cascades):
+            raise sa_exc.ArgumentError(
+                    "Invalid cascade option(s): %s" % 
+                    ", ".join([repr(x) for x in 
+                        sorted(
+                            values.difference(cls._allowed_cascades)
+                    )])
+            )
+
+        if "all" in values:
+            values.update(cls._add_w_all_cascades)
+        if "none" in values:
+            values.clear()
+        values.discard('all')
+
+        self = frozenset.__new__(CascadeOptions, values)
+        self.save_update = 'save-update' in values
+        self.delete = 'delete' in values
+        self.refresh_expire = 'refresh-expire' in values
+        self.merge = 'merge' in values
+        self.expunge = 'expunge' in values
         self.delete_orphan = "delete-orphan" in values
-        if self.delete_orphan:
-            self['delete-orphan'] = True
 
         if self.delete_orphan and not self.delete:
-            util.warn("The 'delete-orphan' cascade option requires "
-                        "'delete'.")
-
-        for x in values:
-            if x not in all_cascades:
-                raise sa_exc.ArgumentError("Invalid cascade option '%s'" % x)
+            util.warn("The 'delete-orphan' cascade "
+                        "option requires 'delete'.")
+        return self
 
     def __repr__(self):
-        return "CascadeOptions(%s)" % repr(",".join(
-            [x for x in ['delete', 'save_update', 'merge', 'expunge',
-                         'delete_orphan', 'refresh-expire']
-             if getattr(self, x, False) is True]))
+        return "CascadeOptions(%r)" % (
+            ",".join([x for x in sorted(self)])
+        )
 
 def _validator_events(desc, key, validator):
     """Runs a validation method on an attribute value to be set or appended."""

File lib/sqlalchemy/schema.py

 
         c.table = selectable
         selectable._columns.add(c)
+        if selectable._is_clone_of is not None:
+            c._is_clone_of = selectable._is_clone_of.columns[c.name]
         if self.primary_key:
             selectable.primary_key.add(c)
         c.dispatch.after_parent_attach(c, selectable)

File lib/sqlalchemy/sql/compiler.py

         # column targeting
         self.result_map = {}
 
+        # collect CTEs to tack on top of a SELECT
+        self.ctes = util.OrderedDict()
+        self.ctes_recursive = False
+
         # true if the paramstyle is positional
         self.positional = dialect.positional
         if self.positional:
         else:
             return self.bindtemplate % {'name':name}
 
+    def visit_cte(self, cte, asfrom=False, ashint=False, 
+                                fromhints=None, **kwargs):
+        if isinstance(cte.name, sql._truncated_label):
+            cte_name = self._truncated_identifier("alias", cte.name)
+        else:
+            cte_name = cte.name
+        if cte.cte_alias:
+            if isinstance(cte.cte_alias, sql._truncated_label):
+                cte_alias = self._truncated_identifier("alias", cte.cte_alias)
+            else:
+                cte_alias = cte.cte_alias
+        if not cte.cte_alias and cte not in self.ctes:
+            if cte.recursive:
+                self.ctes_recursive = True
+            text = self.preparer.format_alias(cte, cte_name)
+            if cte.recursive:
+                if isinstance(cte.original, sql.Select):
+                    col_source = cte.original
+                elif isinstance(cte.original, sql.CompoundSelect):
+                    col_source = cte.original.selects[0]
+                else:
+                    assert False
+                recur_cols = [c.key for c in util.unique_list(col_source.inner_columns)
+                                if c is not None]
+
+                text += "(%s)" % (", ".join(recur_cols))
+            text += " AS \n" + \
+                        cte.original._compiler_dispatch(
+                                self, asfrom=True, **kwargs
+                            )
+            self.ctes[cte] = text
+        if asfrom:
+            if cte.cte_alias:
+                text = self.preparer.format_alias(cte, cte_alias)
+                text += " AS " + cte_name
+            else:
+                return self.preparer.format_alias(cte, cte_name)
+            return text
+
     def visit_alias(self, alias, asfrom=False, ashint=False, 
                                 fromhints=None, **kwargs):
         if asfrom or ashint:
         if select.for_update:
             text += self.for_update_clause(select)
 
+        if self.ctes and \
+            compound_index==1 and not entry:
+            cte_text = self.get_cte_preamble(self.ctes_recursive) + " "
+            cte_text += ", \n".join(
+                [txt for txt in self.ctes.values()]
+            )
+            cte_text += "\n "
+            text = cte_text + text
+
         self.stack.pop(-1)
 
         if asfrom and parens:
         else:
             return text
 
+    def get_cte_preamble(self, recursive):
+        if recursive:
+            return "WITH RECURSIVE"
+        else:
+            return "WITH"
+
     def get_select_precolumns(self, select):
         """Called when building a ``SELECT`` statement, position is just
         before column list.

File lib/sqlalchemy/sql/expression.py

     supports_execution = False
     _from_objects = []
     bind = None
+    _is_clone_of = None
 
     def _clone(self):
         """Create a shallow copy of this ClauseElement.
         f = self
         while f is not None:
             s.add(f)
-            f = getattr(f, '_is_clone_of', None)
+            f = f._is_clone_of
         return s
 
     def __getstate__(self):
                             type_=getattr(self,
                           'type', None))
         co.proxies = [self]
+        if selectable._is_clone_of is not None:
+            co._is_clone_of = \
+                selectable._is_clone_of.columns[key]
         selectable._columns[key] = co
         return co
 
 
         """
 
+        def embedded(expanded_proxy_set, target_set):
+            for t in target_set.difference(expanded_proxy_set):
+                if not set(_expand_cloned([t])
+                            ).intersection(expanded_proxy_set):
+                    return False
+            return True
+
         # dont dig around if the column is locally present
         if self.c.contains_column(column):
             return column
         target_set = column.proxy_set
         cols = self.c
         for c in cols:
-            i = target_set.intersection(itertools.chain(*[p._cloned_set
-                    for p in c.proxy_set]))
+            expanded_proxy_set = set(_expand_cloned(c.proxy_set))
+            i = target_set.intersection(expanded_proxy_set)
             if i and (not require_embedded
-                      or c.proxy_set.issuperset(target_set)):
+                      or embedded(expanded_proxy_set, target_set)):
                 if col is None:
 
                     # no corresponding column yet, pick this one.
     def bind(self):
         return self.element.bind
 
+class CTE(Alias):
+    """Represent a Common Table Expression.
+    
+    The :class:`.CTE` object is obtained using the
+    :meth:`._SelectBase.cte` method from any selectable.
+    See that method for complete examples.
+    
+    New in 0.7.6.
+
+    """
+    __visit_name__ = 'cte'
+    def __init__(self, selectable, 
+                        name=None, 
+                        recursive=False, 
+                        cte_alias=False):
+        self.recursive = recursive
+        self.cte_alias = cte_alias
+        super(CTE, self).__init__(selectable, name=name)
+
+    def alias(self, name=None):
+        return CTE(
+            self.original,
+            name=name,
+            recursive=self.recursive,
+            cte_alias = self.name
+        )
+
+    def union(self, other):
+        return CTE(
+            self.original.union(other),
+            name=self.name,
+            recursive=self.recursive
+        )
+
+    def union_all(self, other):
+        return CTE(
+            self.original.union_all(other),
+            name=self.name,
+            recursive=self.recursive
+        )
+
 
 class _Grouping(ColumnElement):
     """Represent a grouping within a column expression"""
                     is_literal=is_literal
                 )
         c.proxies = [self]
+        if selectable._is_clone_of is not None:
+            c._is_clone_of = \
+                selectable._is_clone_of.columns[c.name]
 
         if attach:
             selectable._columns[c.name] = c
         """
         return self.as_scalar().label(name)
 
+    def cte(self, name=None, recursive=False):
+        """Return a new :class:`.CTE`, or Common Table Expression instance.
+        
+        Common table expressions are a SQL standard whereby SELECT
+        statements can draw upon secondary statements specified along
+        with the primary statement, using a clause called "WITH".
+        Special semantics regarding UNION can also be employed to 
+        allow "recursive" queries, where a SELECT statement can draw 
+        upon the set of rows that have previously been selected.
+        
+        SQLAlchemy detects :class:`.CTE` objects, which are treated
+        similarly to :class:`.Alias` objects, as special elements
+        to be delivered to the FROM clause of the statement as well
+        as to a WITH clause at the top of the statement.
+
+        The :meth:`._SelectBase.cte` method is new in 0.7.6.
+        
+        :param name: name given to the common table expression.  Like
+         :meth:`._FromClause.alias`, the name can be left as ``None``
+         in which case an anonymous symbol will be used at query
+         compile time.
+        :param recursive: if ``True``, will render ``WITH RECURSIVE``.
+         A recursive common table expression is intended to be used in 
+         conjunction with UNION ALL in order to derive rows
+         from those already selected.
+
+        The following examples illustrate two examples from 
+        Postgresql's documentation at
+        http://www.postgresql.org/docs/8.4/static/queries-with.html.
+        
+        Example 1, non recursive::
+        
+            from sqlalchemy import Table, Column, String, Integer, MetaData, \\
+                select, func
+
+            metadata = MetaData()
+
+            orders = Table('orders', metadata,
+                Column('region', String),
+                Column('amount', Integer),
+                Column('product', String),
+                Column('quantity', Integer)
+            )
+
+            regional_sales = select([
+                                orders.c.region, 
+                                func.sum(orders.c.amount).label('total_sales')
+                            ]).group_by(orders.c.region).cte("regional_sales")
+
+
+            top_regions = select([regional_sales.c.region]).\\
+                    where(
+                        regional_sales.c.total_sales > 
+                        select([
+                            func.sum(regional_sales.c.total_sales)/10
+                        ])
+                    ).cte("top_regions")
+
+            statement = select([
+                        orders.c.region, 
+                        orders.c.product, 
+                        func.sum(orders.c.quantity).label("product_units"), 
+                        func.sum(orders.c.amount).label("product_sales")
+                ]).where(orders.c.region.in_(
+                    select([top_regions.c.region])
+                )).group_by(orders.c.region, orders.c.product)
+        
+            result = conn.execute(statement).fetchall()
+            
+        Example 2, WITH RECURSIVE::
+
+            from sqlalchemy import Table, Column, String, Integer, MetaData, \\
+                select, func
+
+            metadata = MetaData()
+
+            parts = Table('parts', metadata,
+                Column('part', String),
+                Column('sub_part', String),
+                Column('quantity', Integer),
+            )
+
+            included_parts = select([
+                                parts.c.sub_part, 
+                                parts.c.part, 
+                                parts.c.quantity]).\\
+                                where(parts.c.part=='our part').\\
+                                cte(recursive=True)
+
+
+            incl_alias = included_parts.alias()
+            parts_alias = parts.alias()
+            included_parts = included_parts.union_all(
+                select([
+                    parts_alias.c.part, 
+                    parts_alias.c.sub_part, 
+                    parts_alias.c.quantity
+                ]).
+                    where(parts_alias.c.part==incl_alias.c.sub_part)
+            )
+
+            statement = select([
+                        included_parts.c.sub_part, 
+                        func.sum(included_parts.c.quantity).label('total_quantity')
+                    ]).\
+                    select_from(included_parts.join(parts,
+                                included_parts.c.part==parts.c.part)).\\
+                    group_by(included_parts.c.sub_part)
+
+            result = conn.execute(statement).fetchall()
+
+        
+        See also:
+        
+        :meth:`.orm.query.Query.cte` - ORM version of :meth:`._SelectBase.cte`.
+
+        """
+        return CTE(self, name=name, recursive=recursive)
+
     @_generative
     @util.deprecated('0.6',
                      message=":func:`.autocommit` is deprecated. Use "
     raise Exception("SQLAlchemy requires Python 2.4 or higher.")
 elif sys.version_info >= (3, 0):
     py3k = True
-    # monkeypatch our preprocessor
-    # onto the 2to3 tool.
-    from sa2to3 import refactor_string
-    from lib2to3.refactor import RefactoringTool
-    RefactoringTool.refactor_string = refactor_string
-
     if has_setuptools:
         extra.update(
             use_2to3=True,
             **kwargs
           )
 
+def monkeypatch2to3():
+    from sa2to3 import refactor_string
+    from lib2to3.refactor import RefactoringTool
+    RefactoringTool.old_refactor_string = RefactoringTool.refactor_string
+    RefactoringTool.refactor_string = refactor_string
+
+def unmonkeypatch2to3():
+    from lib2to3.refactor import RefactoringTool
+    if hasattr(RefactoringTool, 'old_refactor_string'):
+        RefactoringTool.refactor_string = RefactoringTool.old_refactor_string
+
 if pypy or jython or py3k:
-    run_setup(False)
+    if py3k:
+        # monkeypatch our preprocessor onto the 2to3 tool.
+        monkeypatch2to3()
+    try:
+        run_setup(False)
+    finally:
+        if py3k:
+            # unmonkeypatch to not stomp other setup.py's that are compiled
+            # and exec'd and which also require 2to3 fixing
+            unmonkeypatch2to3()
     status_msgs(
         "WARNING: C extensions are not supported on " +
             "this Python platform, speedups are not enabled.",

File test/bootstrap/noseplugin.py

 
         if not issubclass(cls, fixtures.TestBase):
             return False
+        elif cls.__name__.startswith('_'):
+            return False
         else:
             if hasattr(cls, 'setup_class'):
                 existing_setup = cls.setup_class.im_func

File test/lib/fixtures.py

 import sys
 import sqlalchemy as sa
 from test.lib.entities import BasicEntity, ComparableEntity
+from sqlalchemy.ext.declarative import declarative_base, DeclarativeMeta
 
 class TestBase(object):
     # A sequence of database names to always run, regardless of the
 
     @classmethod
     def teardown_class(cls):
-        cls.classes.clear()
-        _ORMTest.teardown_class()
+        cls._teardown_once_class()
         cls._teardown_once_metadata_bind()
 
     def setup(self):
         self._teardown_each_tables()
 
     @classmethod
+    def _teardown_once_class(cls):
+        cls.classes.clear()
+        _ORMTest.teardown_class()
+
+
+    @classmethod
     def _setup_once_classes(cls):
         if cls.run_setup_classes == 'once':
             cls._with_register_classes(cls.setup_classes)
                 cls_registry[classname] = cls
                 return type.__init__(cls, classname, bases, dict_)
 
+
         class _Base(object):
             __metaclass__ = FindFixture
         class Basic(BasicEntity, _Base):
     def setup_mappers(cls):
         pass
 
+class DeclarativeMappedTest(MappedTest):
+    declarative_meta = None
+
+    @classmethod
+    def setup_class(cls):
+        if cls.declarative_meta is None:
+            cls.declarative_meta = sa.MetaData()
+
+        super(DeclarativeMappedTest, cls).setup_class()
+
+    @classmethod
+    def _teardown_once_class(cls):
+        if cls.declarative_meta.tables:
+            cls.declarative_meta.drop_all(testing.db)
+        super(DeclarativeMappedTest, cls)._teardown_once_class()
+
+    @classmethod
+    def _with_register_classes(cls, fn):
+        cls_registry = cls.classes
+        class FindFixtureDeclarative(DeclarativeMeta):
+            def __init__(cls, classname, bases, dict_):
+                cls_registry[classname] = cls
+                return DeclarativeMeta.__init__(
+                        cls, classname, bases, dict_)
+        _DeclBase = declarative_base(metadata=cls.declarative_meta, 
+                            metaclass=FindFixtureDeclarative)
+        class DeclarativeBasic(BasicEntity):
+            pass
+        cls.DeclarativeBasic = _DeclBase
+        fn()
+        if cls.declarative_meta.tables:
+            cls.declarative_meta.create_all(testing.db)

File test/orm/inheritance/_poly_fixtures.py

+from sqlalchemy import Integer, String, ForeignKey, func, desc, and_, or_
+from sqlalchemy.orm import interfaces, relationship, mapper, \
+    clear_mappers, create_session, joinedload, joinedload_all, \
+    subqueryload, subqueryload_all, polymorphic_union, aliased,\
+    class_mapper
+from sqlalchemy import exc as sa_exc
+from sqlalchemy.engine import default
+
+from test.lib import AssertsCompiledSQL, fixtures, testing
+from test.lib.schema import Table, Column
+from test.lib.testing import assert_raises, eq_
+
+class Company(fixtures.ComparableEntity):
+    pass
+class Person(fixtures.ComparableEntity):
+    pass
+class Engineer(Person):
+    pass
+class Manager(Person):
+    pass
+class Boss(Manager):
+    pass
+class Machine(fixtures.ComparableEntity):
+    pass
+class Paperwork(fixtures.ComparableEntity):
+    pass
+
+
+class _PolymorphicFixtureBase(fixtures.MappedTest, AssertsCompiledSQL):
+    run_inserts = 'once'
+    run_setup_mappers = 'once'
+    run_deletes = None
+
+    @classmethod
+    def define_tables(cls, metadata):
+        global people, engineers, managers, boss
+        global companies, paperwork, machines
+
+        companies = Table('companies', metadata,
+            Column('company_id', Integer,
+                primary_key=True,
+                test_needs_autoincrement=True),
+            Column('name', String(50)))
+
+        people = Table('people', metadata,
+            Column('person_id', Integer,
+                primary_key=True,
+                test_needs_autoincrement=True),
+            Column('company_id', Integer,
+                ForeignKey('companies.company_id')),
+            Column('name', String(50)),
+            Column('type', String(30)))
+
+        engineers = Table('engineers', metadata,
+            Column('person_id', Integer,
+                ForeignKey('people.person_id'),
+                primary_key=True),
+            Column('status', String(30)),
+            Column('engineer_name', String(50)),
+            Column('primary_language', String(50)))
+
+        machines = Table('machines', metadata,
+             Column('machine_id',
+                 Integer, primary_key=True,
+                 test_needs_autoincrement=True),
+             Column('name', String(50)),
+             Column('engineer_id', Integer,
+            ForeignKey('engineers.person_id')))
+
+        managers = Table('managers', metadata,
+            Column('person_id', Integer,
+                ForeignKey('people.person_id'),
+                primary_key=True),
+            Column('status', String(30)),
+            Column('manager_name', String(50)))
+
+        boss = Table('boss', metadata,
+            Column('boss_id', Integer,
+                ForeignKey('managers.person_id'),
+                primary_key=True),
+            Column('golf_swing', String(30)))
+
+        paperwork = Table('paperwork', metadata,
+            Column('paperwork_id', Integer,
+                primary_key=True,
+                test_needs_autoincrement=True),
+            Column('description', String(50)),
+            Column('person_id', Integer,
+                ForeignKey('people.person_id')))
+
+    @classmethod
+    def insert_data(cls):
+
+        cls.e1 = e1 = Engineer(
+            name="dilbert",
+            engineer_name="dilbert",
+            primary_language="java",
+            status="regular engineer",
+            paperwork=[
+                Paperwork(description="tps report #1"),
+                Paperwork(description="tps report #2")],
+            machines=[
+                Machine(name='IBM ThinkPad'),
+                Machine(name='IPhone')])
+
+        cls.e2 = e2 = Engineer(
+            name="wally",
+            engineer_name="wally",
+            primary_language="c++",
+            status="regular engineer",
+            paperwork=[
+                Paperwork(description="tps report #3"),
+                Paperwork(description="tps report #4")],
+            machines=[Machine(name="Commodore 64")])
+
+        cls.b1 = b1 = Boss(
+            name="pointy haired boss",
+            golf_swing="fore",
+            manager_name="pointy",
+            status="da boss",
+            paperwork=[Paperwork(description="review #1")])
+
+        cls.m1 = m1 = Manager(
+            name="dogbert",
+            manager_name="dogbert",
+            status="regular manager",
+            paperwork=[
+                Paperwork(description="review #2"),
+                Paperwork(description="review #3")])
+
+        cls.e3 = e3 = Engineer(
+            name="vlad",
+            engineer_name="vlad",
+            primary_language="cobol",
+            status="elbonian engineer",
+            paperwork=[
+                Paperwork(description='elbonian missive #3')],
+            machines=[
+                Machine(name="Commodore 64"),
+                Machine(name="IBM 3270")])
+
+        cls.c1 = c1 = Company(name="MegaCorp, Inc.")
+        c1.employees = [e1, e2, b1, m1]
+        cls.c2 = c2 = Company(name="Elbonia, Inc.")
+        c2.employees = [e3]
+
+        sess = create_session()
+        sess.add(c1)
+        sess.add(c2)
+        sess.flush()
+        sess.expunge_all()
+
+        cls.all_employees = [e1, e2, b1, m1, e3]
+        cls.c1_employees = [e1, e2, b1, m1]
+        cls.c2_employees = [e3]
+
+    def _emps_wo_relationships_fixture(self):
+        return [
+            Engineer(
+                name="dilbert",
+                engineer_name="dilbert",
+                primary_language="java",
+                status="regular engineer"),
+            Engineer(
+                name="wally",
+                engineer_name="wally",
+                primary_language="c++",
+                status="regular engineer"),
+            Boss(
+                name="pointy haired boss",
+                golf_swing="fore",
+                manager_name="pointy",
+                status="da boss"),
+            Manager(
+                name="dogbert",
+                manager_name="dogbert",
+                status="regular manager"),
+            Engineer(
+                name="vlad",
+                engineer_name="vlad",
+                primary_language="cobol",
+                status="elbonian engineer")
+        ]
+
+    @classmethod
+    def setup_mappers(cls):
+        mapper(Company, companies,
+            properties={
+                'employees':relationship(
+                    Person,
+                    order_by=people.c.person_id)})
+
+        mapper(Machine, machines)
+
+        person_with_polymorphic,\
+            manager_with_polymorphic = cls._get_polymorphics()
+
+        mapper(Person, people,
+            with_polymorphic=person_with_polymorphic,
+            polymorphic_on=people.c.type,
+            polymorphic_identity='person',
+            order_by=people.c.person_id,
+            properties={
+                'paperwork':relationship(
+                    Paperwork,
+                    order_by=paperwork.c.paperwork_id)})
+
+        mapper(Engineer, engineers,
+            inherits=Person,
+            polymorphic_identity='engineer',
+            properties={
+                'machines':relationship(
+                    Machine,
+                    order_by=machines.c.machine_id)})
+
+        mapper(Manager, managers,
+            with_polymorphic=manager_with_polymorphic,
+            inherits=Person,
+            polymorphic_identity='manager')
+
+        mapper(Boss, boss,
+            inherits=Manager,
+            polymorphic_identity='boss')
+
+        mapper(Paperwork, paperwork)
+
+class _Polymorphic(_PolymorphicFixtureBase):
+    select_type = ""
+    @classmethod
+    def _get_polymorphics(cls):
+        return None, None
+
+class _PolymorphicPolymorphic(_PolymorphicFixtureBase):
+    select_type = "Polymorphic"
+    @classmethod
+    def _get_polymorphics(cls):
+        return '*', '*'
+
+
+class _PolymorphicUnions(_PolymorphicFixtureBase):
+    select_type = "Unions"
+
+    @classmethod
+    def _get_polymorphics(cls):
+        people, engineers, managers, boss = \
+            cls.tables.people, cls.tables.engineers, \
+            cls.tables.managers, cls.tables.boss
+        person_join = polymorphic_union({
+                'engineer':people.join(engineers),
+                'manager':people.join(managers)},
+            None, 'pjoin')
+        manager_join = people.join(managers).outerjoin(boss)
+        person_with_polymorphic = (
+            [Person, Manager, Engineer], person_join)
+        manager_with_polymorphic = ('*', manager_join)
+        return person_with_polymorphic,\
+            manager_with_polymorphic
+
+
+class _PolymorphicAliasedJoins(_PolymorphicFixtureBase):
+    select_type = "AliasedJoins"
+
+    @classmethod
+    def _get_polymorphics(cls):
+        people, engineers, managers, boss = \
+            cls.tables.people, cls.tables.engineers, \
+            cls.tables.managers, cls.tables.boss
+        person_join = people \
+            .outerjoin(engineers) \
+            .outerjoin(managers) \
+            .select(use_labels=True) \
+            .alias('pjoin')
+        manager_join = people \
+            .join(managers) \
+            .outerjoin(boss) \
+            .select(use_labels=True) \
+            .alias('mjoin')
+        person_with_polymorphic = (
+            [Person, Manager, Engineer], person_join)
+        manager_with_polymorphic = ('*', manager_join)
+        return person_with_polymorphic,\
+            manager_with_polymorphic
+
+
+class _PolymorphicJoins(_PolymorphicFixtureBase):
+    select_type = "Joins"
+
+    @classmethod
+    def _get_polymorphics(cls):
+        people, engineers, managers, boss = \
+            cls.tables.people, cls.tables.engineers, \
+            cls.tables.managers, cls.tables.boss
+        person_join = people.outerjoin(engineers).outerjoin(managers)
+        manager_join = people.join(managers).outerjoin(boss)
+        person_with_polymorphic = (
+            [Person, Manager, Engineer], person_join)
+        manager_with_polymorphic = ('*', manager_join)
+        return person_with_polymorphic,\
+            manager_with_polymorphic

File test/orm/inheritance/test_assorted_poly.py

-"""Very old inheritance-related tests.
-
+"""Miscellaneous inheritance-related tests, many very old.
+These are generally tests derived from specific user issues.
 
 """
 
             }
         )
         assert Dude.supervisor.property.direction is MANYTOONE
-        self._dude_roundtrip()
+        self._dude_roundtrip()
+
+
+class Ticket2419Test(fixtures.DeclarativeMappedTest):
+    """Test [ticket:2419]'s test case."""
+
+    @classmethod
+    def setup_classes(cls):
+        Base = cls.DeclarativeBasic
+        class A(Base):
+            __tablename__ = "a"
+
+            id = Column(Integer, primary_key=True)
+
+        class B(Base):
+            __tablename__ = "b"
+
+            id = Column(Integer, primary_key=True)
+            ds = relationship("D")
+            es = relationship("E")
+
+        class C(A):
+            __tablename__ = "c"
+
+            id = Column(Integer, ForeignKey('a.id'), primary_key=True)
+            b_id = Column(Integer, ForeignKey('b.id'))
+            b = relationship("B", primaryjoin=b_id==B.id)
+
+        class D(Base):
+            __tablename__ = "d"
+
+            id = Column(Integer, primary_key=True)
+            b_id = Column(Integer, ForeignKey('b.id'))
+
+        class E(Base):
+            __tablename__ = 'e'
+            id = Column(Integer, primary_key=True)
+            b_id = Column(Integer, ForeignKey('b.id'))
+
+    def test_join_w_eager_w_any(self):
+        A, B, C, D, E = self.classes.A, self.classes.B, \
+                        self.classes.C, self.classes.D, \
+                        self.classes.E
+        s = Session(testing.db)
+
+        b = B(ds=[D()])
+        s.add_all([
+            C(
+                b=b
+            )
+
+        ])
+
+        s.commit()
+
+        q = s.query(B, B.ds.any(D.id==1)).options(joinedload_all("es"))
+        q = q.join(C, C.b_id==B.id)
+        q = q.limit(5)
+        eq_(
+            q.all(),
+            [(b, True)]
+        )

File test/orm/inheritance/test_polymorphic_rel.py

-from sqlalchemy import Integer, String, ForeignKey, func, desc, and_
+from sqlalchemy import Integer, String, ForeignKey, func, desc, and_, or_
 from sqlalchemy.orm import interfaces, relationship, mapper, \
     clear_mappers, create_session, joinedload, joinedload_all, \
     subqueryload, subqueryload_all, polymorphic_union, aliased,\
 from test.lib.schema import Table, Column
 from test.lib.testing import assert_raises, eq_
 
-class Company(fixtures.ComparableEntity):
-    pass
-class Person(fixtures.ComparableEntity):
-    pass
-class Engineer(Person):
-    pass
-class Manager(Person):
-    pass
-class Boss(Manager):
-    pass
-class Machine(fixtures.ComparableEntity):
-    pass
-class Paperwork(fixtures.ComparableEntity):
-    pass
+from _poly_fixtures import Company, Person, Engineer, Manager, Boss, \
+    Machine, Paperwork, _PolymorphicFixtureBase, _Polymorphic,\
+    _PolymorphicPolymorphic, _PolymorphicUnions, _PolymorphicJoins,\
+    _PolymorphicAliasedJoins
 
-def _produce_test(select_type):
+class _PolymorphicTestBase(object):
 
-    class PolymorphicQueryTest(fixtures.MappedTest, AssertsCompiledSQL):
+    @classmethod
+    def setup_mappers(cls):
+        super(_PolymorphicTestBase, cls).setup_mappers()
+        global people, engineers, managers, boss
+        global companies, paperwork, machines
+        people, engineers, managers, boss,\
+            companies, paperwork, machines = \
+        cls.tables.people, cls.tables.engineers, \
+            cls.tables.managers, cls.tables.boss,\
+            cls.tables.companies, cls.tables.paperwork, cls.tables.machines
 
-        run_inserts = 'once'
-        run_setup_mappers = 'once'
-        run_deletes = None
+    @classmethod
+    def insert_data(cls):
+        super(_PolymorphicTestBase, cls).insert_data()
 
-        @classmethod
-        def define_tables(cls, metadata):
-            global people, engineers, managers, boss
-            global companies, paperwork, machines
+        global all_employees, c1_employees, c2_employees
+        global c1, c2, e1, e2, e3, b1, m1
+        c1, c2, all_employees, c1_employees, c2_employees = \
+            cls.c1, cls.c2, cls.all_employees, \
+                cls.c1_employees, cls.c2_employees
+        e1, e2, e3, b1, m1 = \
+            cls.e1, cls.e2, cls.e3, cls.b1, cls.m1
 
-            companies = Table('companies', metadata,
-                Column('company_id', Integer,
-                    primary_key=True,
-                    test_needs_autoincrement=True),
-                Column('name', String(50)))
+    def test_loads_at_once(self):
+        """
+        Test that all objects load from the full query, when 
+        with_polymorphic is used.
+        """
 
-            people = Table('people', metadata,
-                Column('person_id', Integer,
-                    primary_key=True,
-                    test_needs_autoincrement=True),
-                Column('company_id', Integer,
-                    ForeignKey('companies.company_id')),
-                Column('name', String(50)),
-                Column('type', String(30)))
+        sess = create_session()
+        def go():
+            eq_(sess.query(Person).all(), all_employees)
+        count = {'':14, 'Polymorphic':9}.get(self.select_type, 10)
+        self.assert_sql_count(testing.db, go, count)
 
-            engineers = Table('engineers', metadata,
-                Column('person_id', Integer,
-                    ForeignKey('people.person_id'),
-                    primary_key=True),
-                Column('status', String(30)),
-                Column('engineer_name', String(50)),
-                Column('primary_language', String(50)))
+    def test_primary_eager_aliasing_one(self):
+        # For both joinedload() and subqueryload(), if the original q is 
+        # not loading the subclass table, the joinedload doesn't happen.
 
-            machines = Table('machines', metadata,
-                 Column('machine_id',
-                     Integer, primary_key=True,
-                     test_needs_autoincrement=True),
-                 Column('name', String(50)),
-                 Column('engineer_id', Integer,
-                ForeignKey('engineers.person_id')))
+        sess = create_session()
+        def go():
+            eq_(sess.query(Person)
+                    .options(joinedload(Engineer.machines))[1:3],
+                all_employees[1:3])
+        count = {'':6, 'Polymorphic':3}.get(self.select_type, 4)
+        self.assert_sql_count(testing.db, go, count)
 
-            managers = Table('managers', metadata,
-                Column('person_id', Integer,
-                    ForeignKey('people.person_id'),
-                    primary_key=True),
-                Column('status', String(30)),
-                Column('manager_name', String(50)))
+    def test_primary_eager_aliasing_two(self):
+        sess = create_session()
+        def go():
+            eq_(sess.query(Person)
+                    .options(subqueryload(Engineer.machines)).all(),
+                all_employees)
+        count = {'':14, 'Polymorphic':7}.get(self.select_type, 8)
+        self.assert_sql_count(testing.db, go, count)
 
-            boss = Table('boss', metadata,
-                Column('boss_id', Integer,
-                    ForeignKey('managers.person_id'),
-                    primary_key=True),
-                Column('golf_swing', String(30)))
+    def test_primary_eager_aliasing_three(self):
 
-            paperwork = Table('paperwork', metadata,
-                Column('paperwork_id', Integer,
-                    primary_key=True,
-                    test_needs_autoincrement=True),
-                Column('description', String(50)),
-                Column('person_id', Integer,
-                    ForeignKey('people.person_id')))
+        # assert the JOINs don't over JOIN
 
-            clear_mappers()
+        sess = create_session()
+        def go():
+            eq_(sess.query(Person).with_polymorphic('*')
+                    .options(joinedload(Engineer.machines))[1:3],
+                all_employees[1:3])
+        self.assert_sql_count(testing.db, go, 3)
 
-            mapper(Company, companies,
-                properties={
-                    'employees':relationship(
-                        Person,
-                        order_by=people.c.person_id)})
+        eq_(sess.query(Person).with_polymorphic('*')
+                .options(joinedload(Engineer.machines))
+                .limit(2).offset(1).with_labels()
+                .subquery().count().scalar(),
+            2)
 
-            mapper(Machine, machines)
+    def test_get_one(self):
+        """
+        For all mappers, ensure the primary key has been calculated as 
+        just the "person_id" column.
+        """
+        sess = create_session()
+        eq_(sess.query(Person).get(e1.person_id),
+            Engineer(name="dilbert", primary_language="java"))
 
-            if select_type == '':
-                person_join = manager_join = None
-                person_with_polymorphic = None
-                manager_with_polymorphic = None
-            elif select_type == 'Polymorphic':
-                person_join = manager_join = None
-                person_with_polymorphic = '*'
-                manager_with_polymorphic = '*'
-            elif select_type == 'Unions':
-                person_join = polymorphic_union({
-                        'engineer':people.join(engineers),
-                        'manager':people.join(managers)},
-                    None, 'pjoin')
-                manager_join = people.join(managers).outerjoin(boss)
-                person_with_polymorphic = (
-                    [Person, Manager, Engineer], person_join)
-                manager_with_polymorphic = ('*', manager_join)
-            elif select_type == 'AliasedJoins':
-                person_join = people \
-                    .outerjoin(engineers) \
-                    .outerjoin(managers) \
-                    .select(use_labels=True) \
-                    .alias('pjoin')
-                manager_join = people \
-                    .join(managers) \
-                    .outerjoin(boss) \
-                    .select(use_labels=True) \
-                    .alias('mjoin')
-                person_with_polymorphic = (
-                    [Person, Manager, Engineer], person_join)
-                manager_with_polymorphic = ('*', manager_join)
-            elif select_type == 'Joins':
-                person_join = people.outerjoin(engineers).outerjoin(managers)
-                manager_join = people.join(managers).outerjoin(boss)
-                person_with_polymorphic = (
-                    [Person, Manager, Engineer], person_join)
-                manager_with_polymorphic = ('*', manager_join)
+    def test_get_two(self):
+        sess = create_session()
+        eq_(sess.query(Engineer).get(e1.person_id),
+            Engineer(name="dilbert", primary_language="java"))
 
-            # testing a order_by here as well; 
-            # the surrogate mapper has to adapt it
-            mapper(Person, people,
-                with_polymorphic=person_with_polymorphic,
-                polymorphic_on=people.c.type,
-                polymorphic_identity='person',
-                order_by=people.c.person_id,
-                properties={
-                    'paperwork':relationship(
-                        Paperwork,
-                        order_by=paperwork.c.paperwork_id)})
+    def test_get_three(self):
+        sess = create_session()
+        eq_(sess.query(Manager).get(b1.person_id),
+            Boss(name="pointy haired boss", golf_swing="fore"))
 
-            mapper(Engineer, engineers,
-                inherits=Person,
-                polymorphic_identity='engineer',
-                properties={
-                    'machines':relationship(
-                        Machine,
-                        order_by=machines.c.machine_id)})
-
-            mapper(Manager, managers,
-                with_polymorphic=manager_with_polymorphic,
-                inherits=Person,
-                polymorphic_identity='manager')
-
-            mapper(Boss, boss,
-                inherits=Manager,
-                polymorphic_identity='boss')
-
-            mapper(Paperwork, paperwork)
-
-        @classmethod
-        def insert_data(cls):
-            global all_employees, c1_employees, c2_employees
-            global c1, c2, e1, e2, e3, b1, m1
-
-            e1 = Engineer(
-                name="dilbert",
-                engineer_name="dilbert",
-                primary_language="java",
-                status="regular engineer",
-                paperwork=[
-                    Paperwork(description="tps report #1"),
-                    Paperwork(description="tps report #2")],
-                machines=[
-                    Machine(name='IBM ThinkPad'),
-                    Machine(name='IPhone')])
-
-            e2 = Engineer(
-                name="wally",
-                engineer_name="wally",
-                primary_language="c++",
-                status="regular engineer",
-                paperwork=[
-                    Paperwork(description="tps report #3"),
-                    Paperwork(description="tps report #4")],
-                machines=[Machine(name="Commodore 64")])
-
-            b1 = Boss(
-                name="pointy haired boss",
-                golf_swing="fore",
-                manager_name="pointy",
-                status="da boss",
-                paperwork=[Paperwork(description="review #1")])
-
-            m1 = Manager(
-                name="dogbert",
-                manager_name="dogbert",
-                status="regular manager",
-                paperwork=[
-                    Paperwork(description="review #2"),
-                    Paperwork(description="review #3")])
-
-            e3 = Engineer(
-                name="vlad",
-                engineer_name="vlad",
-                primary_language="cobol",
-                status="elbonian engineer",
-                paperwork=[
-                    Paperwork(description='elbonian missive #3')],
-                machines=[
-                    Machine(name="Commodore 64"),
-                    Machine(name="IBM 3270")])
-
-            c1 = Company(name="MegaCorp, Inc.")
-            c1.employees = [e1, e2, b1, m1]
-            c2 = Company(name="Elbonia, Inc.")
-            c2.employees = [e3]
-
-            sess = create_session()
-            sess.add(c1)
-            sess.add(c2)
-            sess.flush()
-            sess.expunge_all()
-
-            all_employees = [e1, e2, b1, m1, e3]
-            c1_employees = [e1, e2, b1, m1]
-            c2_employees = [e3]
-
-        def test_loads_at_once(self):
-            """
-            Test that all objects load from the full query, when 
-            with_polymorphic is used.
-            """
-
-            sess = create_session()
-            def go():
-                eq_(sess.query(Person).all(), all_employees)
-            count = {'':14, 'Polymorphic':9}.get(select_type, 10)
-            self.assert_sql_count(testing.db, go, count)
-
-        def test_primary_eager_aliasing_one(self):
-            # For both joinedload() and subqueryload(), if the original q is 
-            # not loading the subclass table, the joinedload doesn't happen.
-
-            sess = create_session()
-            def go():
-                eq_(sess.query(Person)
-                        .options(joinedload(Engineer.machines))[1:3],
-                    all_employees[1:3])
-            count = {'':6, 'Polymorphic':3}.get(select_type, 4)
-            self.assert_sql_count(testing.db, go, count)
-
-        def test_primary_eager_aliasing_two(self):
-            sess = create_session()
-            def go():
-                eq_(sess.query(Person)
-                        .options(subqueryload(Engineer.machines)).all(),
-                    all_employees)
-            count = {'':14, 'Polymorphic':7}.get(select_type, 8)
-            self.assert_sql_count(testing.db, go, count)
-
-        def test_primary_eager_aliasing_three(self):
-
-            # assert the JOINs don't over JOIN
-
-            sess = create_session()
-            def go():
-                eq_(sess.query(Person).with_polymorphic('*')
-                        .options(joinedload(Engineer.machines))[1:3],
-                    all_employees[1:3])
-            self.assert_sql_count(testing.db, go, 3)
-
-            eq_(sess.query(Person).with_polymorphic('*')
-                    .options(joinedload(Engineer.machines))
-                    .limit(2).offset(1).with_labels()
-                    .subquery().count().scalar(),
-                2)
-
-        def test_get_one(self):
-            """
-            For all mappers, ensure the primary key has been calculated as 
-            just the "person_id" column.
-            """
-            sess = create_session()
-            eq_(sess.query(Person).get(e1.person_id),
-                Engineer(name="dilbert", primary_language="java"))
-
-        def test_get_two(self):
-            sess = create_session()
-            eq_(sess.query(Engineer).get(e1.person_id),
-                Engineer(name="dilbert", primary_language="java"))
-
-        def test_get_three(self):
-            sess = create_session()
-            eq_(sess.query(Manager).get(b1.person_id),
-                Boss(name="pointy haired boss", golf_swing="fore"))
-
-        def test_multi_join(self):
-            sess = create_session()
-            e = aliased(Person)
-            c = aliased(Company)
-            q = sess.query(Company, Person, c, e)\
-                    .join(Person, Company.employees)\
-                    .join(e, c.employees)\
-                    .filter(Person.name == 'dilbert')\
-                    .filter(e.name == 'wally')
-            eq_(q.count(), 1)
-            eq_(q.all(), [
-                (
-                    Company(company_id=1, name=u'MegaCorp, Inc.'),
-                    Engineer(
-                        status=u'regular engineer',
-                        engineer_name=u'dilbert',
-                        name=u'dilbert',
-                        company_id=1,
-                        primary_language=u'java',
-                        person_id=1,
-                        type=u'engineer'),
-                    Company(company_id=1, name=u'MegaCorp, Inc.'),
-                    Engineer(
-                        status=u'regular engineer',
-                        engineer_name=u'wally',
-                        name=u'wally',
-                        company_id=1,
-                        primary_language=u'c++',
-                        person_id=2,
-                        type=u'engineer')
-                )
-            ])
-
-        def test_filter_on_subclass_one(self):
-            sess = create_session()
-            eq_(sess.query(Engineer).all()[0], Engineer(name="dilbert"))
-
-        def test_filter_on_subclass_two(self):
-            sess = create_session()
-            eq_(sess.query(Engineer).first(), Engineer(name="dilbert"))
-
-        def test_filter_on_subclass_three(self):
-            sess = create_session()
-            eq_(sess.query(Engineer)
-                    .filter(Engineer.person_id == e1.person_id).first(),
-                Engineer(name="dilbert"))
-
-        def test_filter_on_subclass_four(self):
-            sess = create_session()
-            eq_(sess.query(Manager)
-                    .filter(Manager.person_id == m1.person_id).one(),
-                Manager(name="dogbert"))
-
-        def test_filter_on_subclass_five(self):
-            sess = create_session()
-            eq_(sess.query(Manager)
-                    .filter(Manager.person_id == b1.person_id).one(),
-                Boss(name="pointy haired boss"))
-
-        def test_filter_on_subclass_six(self):
-            sess = create_session()
-            eq_(sess.query(Boss)
-                    .filter(Boss.person_id == b1.person_id).one(),
-                Boss(name="pointy haired boss"))
-
-        def test_join_from_polymorphic_nonaliased_one(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=False)
-                    .filter(Paperwork.description.like('%review%')).all(),
-                [b1, m1])
-
-        def test_join_from_polymorphic_nonaliased_two(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=False)
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1, m1])
-
-        def test_join_from_polymorphic_nonaliased_three(self):
-            sess = create_session()
-            eq_(sess.query(Engineer)
-                    .join('paperwork', aliased=False)
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1])
-
-        def test_join_from_polymorphic_nonaliased_four(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=False)
-                    .filter(Person.name.like('%dog%'))
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [m1])
-
-        def test_join_from_polymorphic_aliased_one(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=True)
-                    .filter(Paperwork.description.like('%review%')).all(),
-                [b1, m1])
-
-        def test_join_from_polymorphic_aliased_two(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=True)
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1, m1])
-
-        def test_join_from_polymorphic_aliased_three(self):
-            sess = create_session()
-            eq_(sess.query(Engineer)
-                    .join('paperwork', aliased=True)
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1])
-
-        def test_join_from_polymorphic_aliased_four(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .join('paperwork', aliased=True)
-                    .filter(Person.name.like('%dog%'))
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [m1])
-
-        def test_join_from_with_polymorphic_nonaliased_one(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic(Manager)
-                    .join('paperwork')
-                    .filter(Paperwork.description.like('%review%')).all(),
-                [b1, m1])
-
-        def test_join_from_with_polymorphic_nonaliased_two(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic([Manager, Engineer])
-                    .join('paperwork')
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1, m1])
-
-        def test_join_from_with_polymorphic_nonaliased_three(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic([Manager, Engineer])
-                    .join('paperwork')
-                    .filter(Person.name.like('%dog%'))
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [m1])
-
-
-        def test_join_from_with_polymorphic_aliased_one(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic(Manager)
-                    .join('paperwork', aliased=True)
-                    .filter(Paperwork.description.like('%review%')).all(),
-                [b1, m1])
-
-        def test_join_from_with_polymorphic_aliased_two(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic([Manager, Engineer])
-                    .join('paperwork', aliased=True)
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [e1, m1])
-
-        def test_join_from_with_polymorphic_aliased_three(self):
-            sess = create_session()
-            eq_(sess.query(Person)
-                    .with_polymorphic([Manager, Engineer])
-                    .join('paperwork', aliased=True)
-                    .filter(Person.name.like('%dog%'))
-                    .filter(Paperwork.description.like('%#2%')).all(),
-                [m1])
-
-        def test_join_to_polymorphic_nonaliased(self):
-            sess = create_session()
-            eq_(sess.query(Company)
-                    .join('employees')
-                    .filter(Person.name == 'vlad').one(),
-                c2)
-
-        def test_join_to_polymorphic_aliased(self):
-            sess = create_session()
-            eq_(sess.query(Company)
-                    .join('employees', aliased=True)
-                    .filter(Person.name == 'vlad').one(),
-                c2)
-
-        def test_polymorphic_any_one(self):
-            sess = create_session()
-
-            any_ = Company.employees.any(Person.name == 'vlad')
-            eq_(sess.query(Company).filter(any_).all(), [c2])
-
-        def test_polymorphic_any_two(self):
-            sess = create_session()
-            # test that the aliasing on "Person" does not bleed into the
-            # EXISTS clause generated by any()
-            any_ = Company.employees.any(Person.name == 'wally')
-            eq_(sess.query(Company)
-                    .join(Company.employees, aliased=True)
-                    .filter(Person.name == 'dilbert')
-                    .filter(any_).all(),
-                [c1])
-
-        def test_polymorphic_any_three(self):
-            sess = create_session()
-            any_ = Company.employees.any(Person.name == 'vlad')
-            eq_(sess.query(Company)
-                    .join(Company.employees, aliased=True)
-                    .filter(Person.name == 'dilbert')
-                    .filter(any_).all(),
-                [])
-
-        def test_polymorphic_any_four(self):
-            sess = create_session()
-            any_ = Company.employees.of_type(Engineer).any(
-                Engineer.primary_language == 'cobol')
-            eq_(sess.query(Company).filter(any_).one(), c2)
-
-        def test_polymorphic_any_five(self):
-            sess = create_session()
-            calias = aliased(Company)
-            any_ = calias.employees.of_type(Engineer).any(
-                Engineer.primary_language == 'cobol')
-            eq_(sess.query(calias).filter(any_).one(), c2)
-
-        def test_polymorphic_any_six(self):
-            sess = create_session()
-            any_ = Company.employees.of_type(Boss).any(
-                Boss.golf_swing == 'fore')
-            eq_(sess.query(Company).filter(any_).one(), c1)
-
-        def test_polymorphic_any_seven(self):
-            sess = create_session()
-            any_ = Company.employees.of_type(Boss).any(
-                Manager.manager_name == 'pointy')
-            eq_(sess.query(Company).filter(any_).one(), c1)
-
-        def test_polymorphic_any_eight(self):
-            sess = create_session()
-            if select_type != '':
-                any_ = Engineer.machines.any(
-                    Machine.name == "Commodore 64")
-                eq_(sess.query(Person).filter(any_).all(), [e2, e3])
-
-        def test_polymorphic_any_nine(self):
-            sess = create_session()
-            any_ = Person.paperwork.any(
-                Paperwork.description == "review #2")
-            eq_(sess.query(Person).filter(any_).all(), [m1])
-
-        def test_polymorphic_any_ten(self):
-            sess = create_session()
-            any_ = Company.employees.of_type(Engineer).any(
-                and_(Engineer.primary_language == 'cobol'))
-            eq_(sess.query(Company).filter(any_).one(), c2)
-
-        def test_join_from_columns_or_subclass_one(self):
-            sess = create_session()
-
-            expected = [
-                (u'dogbert',),
-                (u'pointy haired boss',)]
-            eq_(sess.query(Manager.name)
-                    .order_by(Manager.name).all(),
-                expected)
-
-        def test_join_from_columns_or_subclass_two(self):
-            sess = create_session()
-            expected = [
-                (u'dogbert',),
-                (u'dogbert',),
-                (u'pointy haired boss',)]
-            eq_(sess.query(Manager.name)
-                    .join(Paperwork, Manager.paperwork)
-                    .order_by(Manager.name).all(),
-                expected)
-
-        def test_join_from_columns_or_subclass_three(self):
-            sess = create_session()
-            expected = [
-                (u'dilbert',),
-                (u'dilbert',),
-                (u'dogbert',),
-                (u'dogbert',),
-                (u'pointy haired boss',),
-                (u'vlad',),
-                (u'wally',),
-                (u'wally',)]
-            eq_(sess.query(Person.name)
-                    .join(Paperwork, Person.paperwork)
-                    .order_by(Person.name).all(),
-                expected)
-
-        def test_join_from_columns_or_subclass_four(self):
-            sess = create_session()
-            # Load Person.name, joining from Person -> paperwork, get all
-            # the people.
-            expected = [
-                (u'dilbert',),
-                (u'dilbert',),
-                (u'dogbert',),
-                (u'dogbert',),
-                (u'pointy haired boss',),
-                (u'vlad',),
-                (u'wally',),
-                (u'wally',)]
-            eq_(sess.query(Person.name)
-                    .join(paperwork,
-                          Person.person_id == paperwork.c.person_id)
-                    .order_by(Person.name).all(),
-                expected)
-
-        def test_join_from_columns_or_subclass_five(self):
-            sess = create_session()
-            # same, on manager.  get only managers.
-            expected = [
-                (u'dogbert',),
-                (u'dogbert',),
-                (u'pointy haired boss',)]
-            eq_(sess.query(Manager.name)
-                    .join(paperwork,
-                          Manager.person_id == paperwork.c.person_id)
-                    .order_by(Person.name).all(),
-                expected)
-
-        def test_join_from_columns_or_subclass_six(self):
-            sess = create_session()
-            if select_type == '':
-                # this now raises, due to [ticket:1892].  Manager.person_id 
-                # is now the "person_id" column on Manager. SQL is incorrect.
-                assert_raises(
-                    sa_exc.DBAPIError,
-                    sess.query(Person.name)
-                        .join(paperwork,
-                              Manager.person_id == paperwork.c.person_id)
-                        .order_by(Person.name).all)
-            elif select_type == 'Unions':
-                # with the union, not something anyone would really be using 
-                # here, it joins to the full result set.  This is 0.6's 
-                # behavior and is more or less wrong.
-                expected = [
-                    (u'dilbert',),
-                    (u'dilbert',),
-                    (u'dogbert',),
-                    (u'dogbert',),
-                    (u'pointy haired boss',),
-                    (u'vlad',),
-                    (u'wally',),
-                    (u'wally',)]
-                eq_(sess.query(Person.name)
-                        .join(paperwork,
-                              Manager.person_id == paperwork.c.person_id)
-                        .order_by(Person.name).all(),
-                    expected)
-            else:
-                # when a join is present and managers.person_id is available, 
-                # you get the managers.
-                expected = [
-                    (u'dogbert',),
-                    (u'dogbert',),
-                    (u