Commits

Marc Abramowitz  committed 72f8b0c Merge

Merge with upstream

  • Participants
  • Parent commits 75c1d8f, 8b5adc1

Comments (0)

Files changed (98)

 
 0.8.0b1
 =======
+Changes noted below are specific to version 0.8.
+For changes that are in both 0.7 and 0.8, see below
+underneath "0.7.xx".
+
 - general
   - SQLAlchemy 0.8 now targets Python 2.5 and
     above.  Python 2.4 is no longer supported.
   - [removed] The legacy "mutable" system of the
     ORM, including the MutableType class as well
     as the mutable=True flag on PickleType
-    and postgresql.ARRAY has been removed.   
+    and postgresql.ARRAY has been removed.
     In-place mutations are detected by the ORM
     using the sqlalchemy.ext.mutable extension,
     introduced in 0.7.   The removal of MutableType
     a scan of the full contents of the Session 
     when in use. [ticket:2442]
 
+  - [moved] The InstrumentationManager interface
+    and the entire related system of alternate
+    class implementation is now moved out
+    to sqlalchemy.ext.instrumentation.   This is
+    a seldom used system that adds significant 
+    complexity and overhead to the mechanics of 
+    class instrumentation.  The new architecture
+    allows it to remain unused until 
+    InstrumentationManager is actually imported,
+    at which point it is bootstrapped into
+    the core.
+
   - [feature] Major rewrite of relationship() 
     internals now allow join conditions which
     include columns pointing to themselves
     of a join in place of the "of_type()" modifier.
     [ticket:2333]
 
+  - [feature] The of_type() construct on attributes
+    now accepts aliased() class constructs as well
+    as with_polymorphic constructs, and works with
+    query.join(), any(), has(), and also
+    eager loaders subqueryload(), joinedload(),
+    contains_eager()
+    [ticket:2438] [ticket:1106]
+
   - [feature] The "deferred declarative 
     reflection" system has been moved into the 
     declarative extension itself, using the
     Both features should be avoided, however.
     [ticket:2372]
 
-  - [bug] Fixed bug whereby subqueryload() from 
-    a polymorphic mapping to a target would incur
-    a new invocation of the query for each 
-    distinct class encountered in the polymorphic
-    result.  [ticket:2480].  Also in 0.7.8.
-
-  - [bug] Fixed issue in unit of work
-    whereby setting a non-None self-referential
-    many-to-one relationship to None
-    would fail to persist the change if the
-    former value was not already loaded.
-    [ticket:2477]. Also in 0.7.7
-
-  - [bug] Fixed bug in relationship comparisons
-    whereby calling unimplemented methods like
-    SomeClass.somerelationship.like() would
-    produce a recursion overflow, instead
-    of NotImplementedError. Also in 0.7.7.
-
   - [bug] The "passive" flag on Session.is_modified()
     no longer has any effect. is_modified() in 
     all cases looks only at local in-memory
     modified flags and will not emit any
-    SQL or invoke loader callables/initializers.  
+    SQL or invoke loader callables/initializers.
     [ticket:2320]
 
   - [bug] The warning emitted when using 
     would fail to function subsequent to this
     warning in any case.  [ticket:2405]
 
-  - [bug] Fixed bug in declarative 
-    whereby the precedence of columns 
-    in a joined-table, composite
-    column (typically for id) would fail to
-    be correct if the columns contained
-    names distinct from their attribute 
-    names.  This would cause things like
-    primaryjoin conditions made against the
-    entity attributes to be incorrect.  Related
-    to [ticket:1892] as this was supposed
-    to be part of that, this is [ticket:2491].
-    Also in 0.7.8.
-
-  - [feature] The 'objects' argument to 
-    flush() is no longer deprecated, as some
-    valid use cases have been identified.  
-    Also in 0.7.8.
-
-  - [bug] Fixed identity_key() function which 
-    was not accepting a scalar argument 
-    for the identity.  [ticket:2508]. Also
-    in 0.7.8.
-
   - [feature] Query now "auto correlates" by 
     default in the same way as select() does.
     Previously, a Query used as a subquery
     outside.  As always, correlate(None)
     disables correlation.  [ticket:2179]
 
-  - [feature] Added prefix_with() method
-    to Query, calls upon select().prefix_with()
-    to allow placement of MySQL SELECT
-    directives in statements.  Courtesy
-    Diana Clarke [ticket:2443]
-    also in 0.7.7.
-
-  - [bug] Fixed bug in 0.7.6 introduced by 
-    [ticket:2409] whereby column_mapped_collection
-    used against columns that were mapped as
-    joins or other indirect selectables
-    would fail to function.
-    also in 0.7.7.
-
-  - [feature] Added new flag to @validates
-    include_removes.  When True, collection
-    remove and attribute del events
-    will also be sent to the validation function,
-    which accepts an additional argument
-    "is_remove" when this flag is used.
-    also in 0.7.7.
-
   - [feature] The after_attach event is now
     emitted after the object is established
     in Session.new or Session.identity_map
     in these collections when the event 
     is called.  Added before_attach
     event to accommodate use cases that 
-    need autoflush w pre-attached object.  
+    need autoflush w pre-attached object.
     [ticket:2464]
 
-  - [bug] Fixed bug whereby polymorphic_on
-    column that's not otherwise mapped on the 
-    class would be incorrectly included
-    in a merge() operation, raising an error.
-    [ticket:2449]
-    also in 0.7.7.
-
-  - [bug] Fixed bug in expression annotation
-    mechanics which could lead to incorrect
-    rendering of SELECT statements with aliases
-    and joins, particularly when using 
-    column_property().  [ticket:2453]
-    also in 0.7.7.
-
-  - [bug] Fixed bug which would prevent
-    OrderingList from being pickleable
-    [ticket:2454].  Courtesy Jeff Dairiki
-    also in 0.7.7.
-
-  - [bug] Fixed bug whereby populate_existing
-    option would not propagate to subquery
-    eager loaders.  [ticket:2497].  Also
-    in 0.7.8.
+  - [removed] Deprecated identifiers removed:
+
+    * allow_null_pks mapper() argument
+      (use allow_partial_pks)
+
+    * _get_col_to_prop() mapper method
+      (use get_property_by_column())
+
+    * dont_load argument to Session.merge()
+      (use load=True)
+
+    * sqlalchemy.orm.shard module
+      (use sqlalchemy.ext.horizontal_shard)
 
 - engine
-  - [bug] Fixed memory leak in C version of
-    result proxy whereby DBAPIs which don't deliver
-    pure Python tuples for result rows would
-    fail to decrement refcounts correctly.
-    The most prominently affected DBAPI
-    is pyodbc.  Also in 0.7.8.  [ticket:2489]
-
-  - [bug] Fixed bug affecting Py3K whereby
-    string positional parameters passed to 
-    engine/connection execute() would fail to be
-    interpreted correctly, due to __iter__
-    being present on Py3K string.  
-    [ticket:2503].  Also in 0.7.8.
+  - [bug] Fixed bug whereby 
+    a disconnect detect + dispose that occurs
+    when the QueuePool has threads waiting
+    for connections would leave those
+    threads waiting for the duration of 
+    the timeout on the old pool.   The fix
+    now notifies those waiters with a special
+    exception case and has them move onto
+    the new pool.  This fix may or may
+    not be ported to 0.7.  [ticket:2522]
+
+  - [bug] Fixed bug whereby if a database restart
+    affected multiple connections, each 
+    connection would individually invoke a new
+    disposal of the pool, even though only 
+    one disposal is needed.  [ticket:2522]
 
   - [feature] Added a new system
     for registration of new dialects in-process
     argument, preceding "table".   Code which
     uses the 0.7 version of this very new 
     event will need modification to add the 
-    "inspector" object as the first argument.  
+    "inspector" object as the first argument.
     [ticket:2418]
 
   - [feature] The behavior of column targeting
     that aren't in the target table is now an exception.
     [ticket:2415]
 
+  - [feature] Added "MATCH" clause to ForeignKey,
+    ForeignKeyConstraint, courtesy Ryan Kelly.
+    [ticket:2502]
+
+  - [feature] Added support for DELETE and UPDATE from
+    an alias of a table, which would assumedly
+    be related to itself elsewhere in the query,
+    courtesy Ryan Kelly.  [ticket:2507]
+
+  - [feature] select() features a correlate_except()
+    method, auto correlates all selectables except those
+    passed.
+
   - [bug] All of UniqueConstraint, ForeignKeyConstraint,
     CheckConstraint, and PrimaryKeyConstraint will
     attach themselves to their parent table automatically
     column object itself, consistent with the behavior
     of label(column, None).  [ticket:2168]
 
-  - [bug] Removed warning when Index is created
-    with no columns; while this might not be what 
-    the user intended, it is a valid use case 
-    as an Index could be a placeholder for just an 
-    index of a certain name.
-    also in 0.7.7.
-
-  - [feature] Added new connection event
-    dbapi_error(). Is called for all DBAPI-level
-    errors passing the original DBAPI exception
-    before SQLAlchemy modifies the state 
-    of the cursor.
-    also in 0.7.7.
-
-  - [bug] If conn.begin() fails when calling
-    "with engine.begin()", the newly acquired
-    Connection is closed explicitly before 
-    propagating the exception onward normally.
-    also in 0.7.7.
-
-  - [bug] Added BIGINT, BINARY, VARBINARY to 
-    types.__all__, sqlalchemy namespaces,
-    plus tests to make sure new types 
-    remain importable.  [ticket:2474] 
-    also in 0.7.7, [ticket:2499] also 
-    in 0.7.8.
-
-  - [bug] Repaired common table expression
-    rendering to function correctly when the 
-    SELECT statement contains UNION or other
-    compound expressions, courtesy btbuilder.  
-    [ticket:2490]  Also in 0.7.8.
-
-  - [bug] Fixed bug whereby append_column()
-    wouldn't function correctly on a cloned
-    select() construct, courtesy 
-    Gunnlaugur Þór Briem.  [ticket:2482]
-    Also in 0.7.8.
-
 - sqlite
   - [feature] the SQLite date and time types
     have been overhauled to support a more open
     Nathan Wright for the work and tests on
     this.  [ticket:2363]
 
-  - [feature] Added SQLite execution option
-    "sqlite_raw_colnames=True", will bypass
-    attempts to remove "." from column names
-    returned by SQLite cursor.description.
-    [ticket:2475] Also in 0.7.7.
-
 - mssql
   - [bug] removed legacy behavior whereby 
     a column comparison to a scalar SELECT via 
     needs to be modified to use column.in_(select)
     explicitly.  [ticket:2277]
 
+- postgresql
+
+  - [feature] postgresql.ARRAY features an optional
+    "dimension" argument, will assign a specific
+    number of dimensions to the array which will
+    render in DDL as ARRAY[][]..., also improves
+    performance of bind/result processing.
+    [ticket:2441]
+
+  - [feature] Added support for the Postgresql ONLY
+    keyword, which can appear corresponding to a 
+    table in a SELECT, UPDATE, or DELETE statement.
+    The phrase is established using with_hint().
+    Courtesy Ryan Kelly [ticket:2506]
+
+
+- mysql
+  - [bug] Dialect no longer emits expensive server
+    collations query, as well as server casing,
+    on first connect.  These functions are still 
+    available as semi-private. [ticket:2404]
+
+- oracle
+  - [bug] Quoting information is now passed along
+    from a Column with quote=True when generating
+    a same-named bound parameter to the bindparam()
+    object, as is the case in generated INSERT and UPDATE 
+    statements, so that unknown reserved names can 
+    be fully supported.  [ticket:2437]
+
+- extensions
+  - [removed] The SQLSoup extension is removed from 
+    SQLAlchemy, and is now an external project.
+    See http://pypi.python.org/pypi/sqlsoup .
+    [ticket:2262]
+
+0.7.7 - 0.7.xx
+==============
+0.8 development begins during 0.7.7 development.
+All relevant bug fixes 
+and features listed below from version 0.7.7 on 
+are also present in 0.8.
+
+0.7.9
+=====
+- sql
+  - [bug] Fixed CTE bug whereby positional 
+    bound parameters present in the CTEs themselves
+    would corrupt the overall ordering of 
+    bound parameters.  This primarily
+    affected SQL Server as the platform with 
+    positional binds + CTE support.  
+    [ticket:2521]
+
+  - [bug] quoting is applied to the column names
+    inside the WITH RECURSIVE clause of a 
+    common table expression according to the 
+    quoting rules for the originating Column.
+    [ticket:2512]
+
+  - [bug] Fixed regression introduced in 0.7.6 
+    whereby the FROM list of a SELECT statement
+    could be incorrect in certain "clone+replace"
+    scenarios.  [ticket:2518]
+
+- engine
+  - [feature] Dramatic improvement in memory
+    usage of the event system; instance-level
+    collections are no longer created for a
+    particular type of event until 
+    instance-level listeners are established 
+    for that event.  [ticket:2516]
+
+0.7.8
+=====
+- orm
+  - [bug] Fixed bug whereby subqueryload() from 
+    a polymorphic mapping to a target would incur
+    a new invocation of the query for each 
+    distinct class encountered in the polymorphic
+    result.  [ticket:2480]
+
+  - [bug] Fixed bug in declarative 
+    whereby the precedence of columns 
+    in a joined-table, composite
+    column (typically for id) would fail to
+    be correct if the columns contained
+    names distinct from their attribute 
+    names.  This would cause things like
+    primaryjoin conditions made against the
+    entity attributes to be incorrect.  Related
+    to [ticket:1892] as this was supposed
+    to be part of that, this is [ticket:2491].
+
+  - [feature] The 'objects' argument to 
+    flush() is no longer deprecated, as some
+    valid use cases have been identified.
+
+  - [bug] Fixed identity_key() function which 
+    was not accepting a scalar argument 
+    for the identity.  [ticket:2508].
+
+  - [bug] Fixed bug whereby populate_existing
+    option would not propagate to subquery
+    eager loaders.  [ticket:2497].
+
+- sql
+  - [bug] added BIGINT to types.__all__,
+    BIGINT, BINARY, VARBINARY to sqlalchemy
+    module namespace, plus test to ensure
+    this breakage doesn't occur again.
+    [ticket:2499]
+
+  - [bug] Repaired common table expression
+    rendering to function correctly when the 
+    SELECT statement contains UNION or other
+    compound expressions, courtesy btbuilder.
+    [ticket:2490]
+
+  - [bug] Fixed bug whereby append_column()
+    wouldn't function correctly on a cloned
+    select() construct, courtesy 
+    Gunnlaugur Þór Briem.  [ticket:2482]
+
+- engine
+  - [bug] Fixed memory leak in C version of
+    result proxy whereby DBAPIs which don't deliver
+    pure Python tuples for result rows would
+    fail to decrement refcounts correctly.
+    The most prominently affected DBAPI
+    is pyodbc.  [ticket:2489]
+
+  - [bug] Fixed bug affecting Py3K whereby
+    string positional parameters passed to 
+    engine/connection execute() would fail to be
+    interpreted correctly, due to __iter__
+    being present on Py3K string.
+    [ticket:2503].
+
+- postgresql
+  - [bug] removed unnecessary table clause when
+    reflecting enums, [ticket:2510].  Courtesy
+    Gunnlaugur Þór Briem.
+
+- oracle
+  - [bug] Added ROWID to oracle.*, [ticket:2483]
+
+- mysql
+  - [feature] Added a new dialect for Google App
+    Engine.  Courtesy Richie Foreman. [ticket:2484]
+
+
+0.7.7
+=====
+- orm
+  - [bug] Fixed issue in unit of work
+    whereby setting a non-None self-referential
+    many-to-one relationship to None
+    would fail to persist the change if the
+    former value was not already loaded.
+    [ticket:2477].
+
+  - [feature] Added prefix_with() method
+    to Query, calls upon select().prefix_with()
+    to allow placement of MySQL SELECT
+    directives in statements.  Courtesy
+    Diana Clarke [ticket:2443]
+
+  - [bug] Fixed bug in 0.7.6 introduced by 
+    [ticket:2409] whereby column_mapped_collection
+    used against columns that were mapped as
+    joins or other indirect selectables
+    would fail to function.
+
+  - [feature] Added new flag to @validates
+    include_removes.  When True, collection
+    remove and attribute del events
+    will also be sent to the validation function,
+    which accepts an additional argument
+    "is_remove" when this flag is used.
+
+  - [bug] Fixed bug whereby polymorphic_on
+    column that's not otherwise mapped on the 
+    class would be incorrectly included
+    in a merge() operation, raising an error.
+    [ticket:2449]
+
+  - [bug] Fixed bug in expression annotation
+    mechanics which could lead to incorrect
+    rendering of SELECT statements with aliases
+    and joins, particularly when using 
+    column_property().  [ticket:2453]
+
+  - [bug] Fixed bug which would prevent
+    OrderingList from being pickleable
+    [ticket:2454].  Courtesy Jeff Dairiki
+
+  - [bug] Fixed bug in relationship comparisons
+    whereby calling unimplemented methods like
+    SomeClass.somerelationship.like() would
+    produce a recursion overflow, instead
+    of NotImplementedError.
+
+- sql
+  - [bug] Removed warning when Index is created
+    with no columns; while this might not be what 
+    the user intended, it is a valid use case 
+    as an Index could be a placeholder for just an 
+    index of a certain name.
+
+  - [feature] Added new connection event
+    dbapi_error(). Is called for all DBAPI-level
+    errors passing the original DBAPI exception
+    before SQLAlchemy modifies the state 
+    of the cursor.
+
+  - [bug] If conn.begin() fails when calling
+    "with engine.begin()", the newly acquired
+    Connection is closed explicitly before 
+    propagating the exception onward normally.
+
+  - [bug] Add BINARY, VARBINARY to types.__all__,
+    [ticket:2474]
+
+- mssql
   - [feature] Added interim create_engine flag
     supports_unicode_binds to PyODBC dialect,
     to force whether or not the dialect
     passes Python unicode literals to PyODBC 
     or not.
-    also in 0.7.7.
 
   - [bug] Repaired the use_scope_identity
     create_engine() flag when using the pyodbc
     INSERT to get at the last inserted ID,
     for those tables which have "implicit_returning"
     set to False.
-    also in 0.7.7.
  
   - [bug] UPDATE..FROM syntax with SQL Server
     requires that the updated table be present
     in the FROM, when FROM is present 
     in the first place.  Courtesy sayap.
     [ticket:2468]
-    also in 0.7.7.
 
 - postgresql
   - [feature] Added new for_update/with_lockmode()
     with_lockmode("read_nowait").
     These emit "FOR SHARE" and "FOR SHARE NOWAIT",
     respectively.  Courtesy Diana Clarke 
-    [ticket:2445] Also in 0.7.7.
-
-  - [feature] postgresql.ARRAY features an optional
-    "dimension" argument, will assign a specific
-    number of dimensions to the array which will
-    render in DDL as ARRAY[][]..., also improves
-    performance of bind/result processing.
-    [ticket:2441]
+    [ticket:2445]
 
   - [bug] removed unnecessary table clause
     when reflecting domains, [ticket:2473]
-    also in 0.7.7
-
-  - [bug] removed unnecessary table clause when
-    reflecting enums, [ticket:2510].  Courtesy
-    Gunnlaugur Þór Briem.  Also in 0.7.8.
 
 - mysql
   - [bug] Fixed bug whereby column name inside 
     column with InnoDB would double quote a 
     name that's a reserved word.  Courtesy Jeff
     Dairiki. [ticket:2460]
-    also in 0.7.7.
 
   - [bug] Fixed bug whereby get_view_names() for
     "information_schema" schema would fail
     to retrieve views marked as "SYSTEM VIEW".
     courtesy Matthew Turland.
-    also in 0.7.7.
 
   - [bug] Fixed bug whereby if cast() is used
     on a SQL expression whose type is not supported
     if the casted expression required that it be
     grouped; grouping is now applied to those
     expressions.  [ticket:2467]
-    also in 0.7.7.
-
-  - [bug] Dialect no longer emits expensive server
-    collations query, as well as server casing,
-    on first connect.  These functions are still 
-    available as semi-private. [ticket:2404]
-
-  - [feature] Added a new dialect for Google App
-    Engine.  Courtesy Richie Foreman. 
-    Also in 0.7.8.  [ticket:2484]
-
-- oracle
-  - [bug] Quoting information is now passed along
-    from a Column with quote=True when generating
-    a same-named bound parameter to the bindparam()
-    object, as is the case in generated INSERT and UPDATE 
-    statements, so that unknown reserved names can 
-    be fully supported.  [ticket:2437]
-
-  - [bug] Added ROWID to oracle.*, [ticket:2483]
-    Also in 0.7.8.
-
-- extensions
-  - [removed] The SQLSoup extension is removed from 
-    SQLAlchemy, and is now an external project.
-    See http://pypi.python.org/pypi/sqlsoup .
-    [ticket:2262]
-
-0.7.7 - 0.7.xx
-==============
-
-Changes which apply to 0.7.7 and subsequent versions of 0.7
-are listed in the CHANGES file within the 0.7 branch.  All
-those changes which are also in the 0.8 series (which is typically
-all of them) are listed inline within the 0.8 changes above,
-those which apply to an 0.7 release are noted.
+
+- sqlite
+
+  - [feature] Added SQLite execution option
+    "sqlite_raw_colnames=True", will bypass
+    attempts to remove "." from column names
+    returned by SQLite cursor.description.
+    [ticket:2475]
 
 0.7.6
 =====
     would not get the appropriate collection
     instrumentation if it were only used
     in a custom subclass that used
-    @collection.internally_instrumented.  
+    @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.  
+    derived function in the columns clause.
     [ticket:2419]
 
   - [bug] Fixed the repr() for CascadeOptions to
 
   - [feature] Added the ability to query for
     Table-bound column names when using 
-    query(sometable).filter_by(colname=value).  
+    query(sometable).filter_by(colname=value).
     [ticket:2400]
 
   - [bug] Improved the "declarative reflection" 
   - [bug] Fixed bug whereby event.listen(SomeClass)
     forced an entirely unnecessary compile of the 
     mapper, making events very hard to set up
-    at module import time (nobody noticed this ??)  
+    at module import time (nobody noticed this ??)
     [ticket:2367]
 
   - [bug] Fixed bug whereby hybrid_property didn't 
 - engine
   - [bug] Added __reduce__ to StatementError, 
     DBAPIError, column errors so that exceptions 
-    are pickleable, as when using multiprocessing.  
+    are pickleable, as when using multiprocessing.
     However, not 
     all DBAPIs support this yet, such as 
     psycopg2. [ticket:2371]

File doc/build/index.rst

   :doc:`Deprecated Event Interfaces <orm/deprecated>` |
   :doc:`ORM Exceptions <orm/exceptions>` |
   :doc:`Horizontal Sharding <orm/extensions/horizontal_shard>` |
+  :doc:`Alternate Instrumentation <orm/extensions/instrumentation>`
 
 SQLAlchemy Core
 ===============

File doc/build/orm/deprecated.rst

 .. autoclass:: AttributeExtension
     :members:
 
-## In 0.7, move "interfaces" to here.

File doc/build/orm/events.rst

 .. autoclass:: sqlalchemy.orm.events.InstrumentationEvents
    :members:
 
-Alternate Class Instrumentation
--------------------------------
-
-.. autoclass:: sqlalchemy.orm.interfaces.InstrumentationManager
-    :members:
-    :undoc-members:
-
-

File doc/build/orm/extensions/index.rst

     orderinglist
     horizontal_shard
     hybrid
+    instrumentation
 

File doc/build/orm/extensions/instrumentation.rst

+.. _instrumentation_toplevel:
+
+Alternate Class Instrumentation
+================================
+
+.. automodule:: sqlalchemy.ext.instrumentation
+
+API Reference
+-------------
+
+.. autodata:: INSTRUMENTATION_MANAGER
+
+.. autoclass:: InstrumentationManager
+    :members:
+    :undoc-members:
+
+.. autodata:: instrumentation_finders
+
+.. autoclass:: ExtendedInstrumentationRegistry
+    :show-inheritance:
+    :members:
+
+
+

File doc/build/orm/inheritance.rst

 
     FROM x JOIN (SELECT * FROM y JOIN z ON <onclause>) AS anon_1 ON <onclause>
 
+The above join can also be expressed more succinctly by combining ``of_type()``
+with the polymorphic construct::
+
+    manager_and_engineer = with_polymorphic(
+                                Employee, [Manager, Engineer], 
+                                aliased=True)
+
+    session.query(Company).\
+        join(Company.employees.of_type(manager_and_engineer)).\
+        filter(
+            or_(manager_and_engineer.Engineer.engineer_info=='someinfo', 
+                manager_and_engineer.Manager.manager_data=='somedata')
+        )
+
 The ``any()`` and ``has()`` operators also can be used with
 :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` when the embedded
 criterion is in terms of a subclass::
 ``engineers``, and also specifies criterion which correlates the EXISTS
 subselect back to the parent ``companies`` table.
 
+.. versionadded:: 0.8
+   :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type` accepts
+   :func:`.orm.aliased` and :func:`.orm.with_polymorphic` constructs in conjunction
+   with :meth:`.Query.join`, ``any()`` and ``has()``.
+
+Eager Loading of Specific Subtypes
+++++++++++++++++++++++++++++++++++
+
+The :func:`.joinedload` and :func:`.subqueryload` options also support
+paths which make use of :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type`.
+Below we load ``Company`` rows while eagerly loading related ``Engineer`` 
+objects, querying the ``employee`` and ``engineer`` tables simultaneously::
+
+    session.query(Company).\
+        options(subqueryload_all(Company.employees.of_type(Engineer), 
+                        Engineer.machines))
+
+.. versionadded:: 0.8
+    :func:`.joinedload` and :func:`.subqueryload` support
+    paths that are qualified with 
+    :func:`~sqlalchemy.orm.interfaces.PropComparator.of_type`.
+
 Single Table Inheritance
 ------------------------
 

File doc/build/orm/relationships.rst

                         secondary="association", 
                         backref="parents")
 
+Deleting Rows from the Many to Many Table
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+A behavior which is unique to the ``secondary`` argument to :func:`.relationship`
+is that the :class:`.Table` which is specified here is automatically subject 
+to INSERT and DELETE statements, as objects are added or removed from the collection.
+There is **no need to delete from this table manually**.   The act of removing a 
+record from the collection will have the effect of the row being deleted on flush::
+
+    # row will be deleted from the "secondary" table
+    # automatically
+    myparent.children.remove(somechild)
+
+A question which often arises is how the row in the "secondary" table can be deleted
+when the child object is handed directly to :meth:`.Session.delete`::
+
+    session.delete(somechild)
+
+There are several possibilities here:
+
+* If there is a :func:`.relationship` from ``Parent`` to ``Child``, but there is 
+  **not** a reverse-relationship that links a particular ``Child`` to each ``Parent``,
+  SQLAlchemy will not have any awareness that when deleting this particular
+  ``Child`` object, it needs to maintain the "secondary" table that links it to
+  the ``Parent``.  No delete of the "secondary" table will occur.
+* If there is a relationship that links a particular ``Child`` to each ``Parent``,
+  suppose it's called ``Child.parents``, SQLAlchemy by default will load in 
+  the ``Child.parents`` collection to locate all ``Parent`` objects, and remove
+  each row from the "secondary" table which establishes this link.  Note that
+  this relationship does not need to be bidrectional; SQLAlchemy is strictly
+  looking at every :func:`.relationship` associated with the ``Child`` object
+  being deleted.
+* A higher performing option here is to use ON DELETE CASCADE directives 
+  with the foreign keys used by the database.   Assuming the database supports
+  this feature, the database itself can be made to automatically delete rows in the 
+  "secondary" table as referencing rows in "child" are deleted.   SQLAlchemy
+  can be instructed to forego actively loading in the ``Child.parents`` 
+  collection in this case using the ``passive_deletes=True`` directive
+  on :meth:`.relationship`; see :ref:`passive_deletes` for more details
+  on this.
+
+Note again, these behaviors are *only* relevant to the ``secondary`` option
+used with :func:`.relationship`.   If dealing with association tables that
+are mapped explicitly and are *not* present in the ``secondary`` option
+of a relevant :func:`.relationship`, cascade rules can be used instead
+to automatically delete entities in reaction to a related entity being
+deleted - see :ref:`unitofwork_cascades` for information on this feature.
+
+
 .. _association_pattern:
 
 Association Object

File examples/custom_attributes/custom_management.py

-"""this example illustrates how to replace SQLAlchemy's class descriptors with
-a user-defined system.
+"""Illustrates customized class instrumentation, using
+the :mod:`sqlalchemy.ext.instrumentation` extension package.
 
-This sort of thing is appropriate for integration with frameworks that
-redefine class behaviors in their own way, such that SQLA's default
-instrumentation is not compatible.
+In this example, mapped classes are modified to 
+store their state in a dictionary attached to an attribute
+named "_goofy_dict", instead of using __dict__.
+this example illustrates how to replace SQLAlchemy's class 
+descriptors with a user-defined system.
 
-The example illustrates redefinition of instrumentation at the class level as
-well as the collection level, and redefines the storage of the class to store
-state within "instance._goofy_dict" instead of "instance.__dict__". Note that
-the default collection implementations can be used with a custom attribute
-system as well.
 
 """
 from sqlalchemy import create_engine, MetaData, Table, Column, Integer, Text,\
     ForeignKey
-from sqlalchemy.orm import mapper, relationship, Session,\
-    InstrumentationManager
+from sqlalchemy.orm import mapper, relationship, Session
 
 from sqlalchemy.orm.attributes import set_attribute, get_attribute, \
     del_attribute
 from sqlalchemy.orm.instrumentation import is_instrumented
-from sqlalchemy.orm.collections import collection_adapter
 
+from sqlalchemy.ext.instrumentation import InstrumentationManager
 
 class MyClassState(InstrumentationManager):
-    def __init__(self, cls):
-        self.states = {}
-
-    def instrument_attribute(self, class_, key, attr):
-        pass
-
-    def install_descriptor(self, class_, key, attr):
-        pass
-
-    def uninstall_descriptor(self, class_, key, attr):
-        pass
-
-    def instrument_collection_class(self, class_, key, collection_class):
-        return MyCollection
-
     def get_instance_dict(self, class_, instance):
         return instance._goofy_dict
 
     def initialize_instance_dict(self, class_, instance):
         instance.__dict__['_goofy_dict'] = {}
 
-    def initialize_collection(self, key, state, factory):
-        data = factory()
-        return MyCollectionAdapter(key, state, data), data
-
     def install_state(self, class_, instance, state):
-        self.states[id(instance)] = state
+        instance.__dict__['_goofy_dict']['state'] = state
 
     def state_getter(self, class_):
         def find(instance):
-            return self.states[id(instance)]
+            return instance.__dict__['_goofy_dict']['state']
         return find
 
 class MyClass(object):
         else:
             del self._goofy_dict[key]
 
-class MyCollectionAdapter(object):
-    """An wholly alternative instrumentation implementation."""
-
-    def __init__(self, key, state, collection):
-        self.key = key
-        self.state = state
-        self.collection = collection
-        setattr(collection, '_sa_adapter', self)
-
-    def unlink(self, data):
-        setattr(data, '_sa_adapter', None)
-
-    def adapt_like_to_iterable(self, obj):
-        return iter(obj)
-
-    def append_with_event(self, item, initiator=None):
-        self.collection.add(item, emit=initiator)
-
-    def append_multiple_without_event(self, items):
-        self.collection.members.extend(items)
-
-    def append_without_event(self, item):
-        self.collection.add(item, emit=False)
-
-    def remove_with_event(self, item, initiator=None):
-        self.collection.remove(item, emit=initiator)
-
-    def remove_without_event(self, item):
-        self.collection.remove(item, emit=False)
-
-    def clear_with_event(self, initiator=None):
-        for item in list(self):
-            self.remove_with_event(item, initiator)
-    def clear_without_event(self):
-        for item in list(self):
-            self.remove_without_event(item)
-    def __iter__(self):
-        return iter(self.collection)
-
-    def fire_append_event(self, item, initiator=None):
-        if initiator is not False and item is not None:
-            self.state.get_impl(self.key).\
-                        fire_append_event(self.state, self.state.dict, item,
-                                                        initiator)
-
-    def fire_remove_event(self, item, initiator=None):
-        if initiator is not False and item is not None:
-            self.state.get_impl(self.key).\
-                        fire_remove_event(self.state, self.state.dict, item,
-                                                        initiator)
-
-    def fire_pre_remove_event(self, initiator=None):
-        self.state.get_impl(self.key).\
-                        fire_pre_remove_event(self.state, self.state.dict, 
-                                                        initiator)
-
-class MyCollection(object):
-    def __init__(self):
-        self.members = list()
-    def add(self, object, emit=None):
-        self.members.append(object)
-        collection_adapter(self).fire_append_event(object, emit)
-    def remove(self, object, emit=None):
-        collection_adapter(self).fire_pre_remove_event(object)
-        self.members.remove(object)
-        collection_adapter(self).fire_remove_event(object, emit)
-    def __getitem__(self, index):
-        return self.members[index]
-    def __iter__(self):
-        return iter(self.members)
-    def __len__(self):
-        return len(self.members)
 
 if __name__ == '__main__':
     meta = MetaData(create_engine('sqlite://'))
 
     assert a1.name == 'a1'
     assert a1.bs[0].name == 'b1'
-    assert isinstance(a1.bs, MyCollection)
 
     sess = Session()
     sess.add(a1)
 
     assert a1.name == 'a1'
     assert a1.bs[0].name == 'b1'
-    assert isinstance(a1.bs, MyCollection)
 
     a1.bs.remove(a1.bs[0])
 

File lib/sqlalchemy/__init__.py

 import inspect as _inspect
 import sys
 
-from sqlalchemy.sql import (
+from .sql import (
     alias,
     and_,
     asc,
     update,
     )
 
-from sqlalchemy.types import (
+from .types import (
     BIGINT,
     BINARY,
     BLOB,
     )
 
 
-from sqlalchemy.schema import (
+from .schema import (
     CheckConstraint,
     Column,
     ColumnDefault,
     UniqueConstraint,
     )
 
-from sqlalchemy.inspection import inspect
+from .inspection import inspect
 
-from sqlalchemy.engine import create_engine, engine_from_config
+from .engine import create_engine, engine_from_config
 
 
 __all__ = sorted(name for name, obj in locals().items()
 
 del _inspect, sys
 
-from sqlalchemy import util as _sa_util
+from . import util as _sa_util
 _sa_util.importlater.resolve_all()

File lib/sqlalchemy/connectors/mxodbc.py

 import re
 import warnings
 
-from sqlalchemy.connectors import Connector
+from . import Connector
 
 class MxODBCConnector(Connector):
     driver='mxodbc'

File lib/sqlalchemy/connectors/mysqldb.py

 
 """
 
-from sqlalchemy.connectors import Connector
-from sqlalchemy.engine import base as engine_base, default
-from sqlalchemy.sql import operators as sql_operators
-from sqlalchemy import exc, log, schema, sql, types as sqltypes, util
-from sqlalchemy import processors
+from . import Connector
+from ..engine import base as engine_base, default
+from ..sql import operators as sql_operators
+from .. import exc, log, schema, sql, types as sqltypes, util, processors
 import re
 
 # the subclassing of Connector by all classes

File lib/sqlalchemy/connectors/pyodbc.py

 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-from sqlalchemy.connectors import Connector
-from sqlalchemy.util import asbool
+from . import Connector
+from ..util import asbool
 
 import sys
 import re

File lib/sqlalchemy/connectors/zxJDBC.py

 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 import sys
-from sqlalchemy.connectors import Connector
+from . import Connector
 
 class ZxJDBCConnector(Connector):
     driver = 'zxjdbc'

File lib/sqlalchemy/databases/__init__.py

 compatibility with pre 0.6 versions.
 
 """
-from sqlalchemy.dialects.sqlite import base as sqlite
-from sqlalchemy.dialects.postgresql import base as postgresql
+from ..dialects.sqlite import base as sqlite
+from ..dialects.postgresql import base as postgresql
 postgres = postgresql
-from sqlalchemy.dialects.mysql import base as mysql
-from sqlalchemy.dialects.drizzle import base as drizzle
-from sqlalchemy.dialects.oracle import base as oracle
-from sqlalchemy.dialects.firebird import base as firebird
-from sqlalchemy.dialects.maxdb import base as maxdb
-from sqlalchemy.dialects.informix import base as informix
-from sqlalchemy.dialects.mssql import base as mssql
-from sqlalchemy.dialects.access import base as access
-from sqlalchemy.dialects.sybase import base as sybase
+from ..dialects.mysql import base as mysql
+from ..dialects.drizzle import base as drizzle
+from ..dialects.oracle import base as oracle
+from ..dialects.firebird import base as firebird
+from ..dialects.maxdb import base as maxdb
+from ..dialects.informix import base as informix
+from ..dialects.mssql import base as mssql
+from ..dialects.access import base as access
+from ..dialects.sybase import base as sybase
 
 
 __all__ = (

File lib/sqlalchemy/dialects/__init__.py

     'sybase',
     )
 
-from sqlalchemy import util
+from .. import util
 
 def _auto_fn(name):
     """default dialect importer.

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

         else:
             return None
 
-    def visit_table(self, table, mssql_aliased=False, **kwargs):
-        if mssql_aliased is table:
+    def visit_table(self, table, mssql_aliased=False, iscrud=False, **kwargs):
+        if mssql_aliased is table or iscrud:
             return super(MSSQLCompiler, self).visit_table(table, **kwargs)
 
         # alias schema-qualified tables

File lib/sqlalchemy/dialects/oracle/cx_oracle.py

         return dbapi.ROWID
 
 class OracleCompiler_cx_oracle(OracleCompiler):
-    def bindparam_string(self, name, quote=None):
+    def bindparam_string(self, name, quote=None, **kw):
         if quote is True or quote is not False and \
             self.preparer._bindparam_requires_quotes(name):
             quoted_name = '"%s"' % name
             self._quoted_bind_names[name] = quoted_name
-            return OracleCompiler.bindparam_string(self, quoted_name)
+            return OracleCompiler.bindparam_string(self, quoted_name, **kw)
         else:
-            return OracleCompiler.bindparam_string(self, name)
+            return OracleCompiler.bindparam_string(self, name, **kw)
 
 
 class OracleExecutionContext_cx_oracle(OracleExecutionContext):

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

         where(table.c.name=='foo')
     print result.fetchall()
 
+FROM ONLY ...
+------------------------
+
+The dialect supports PostgreSQL's ONLY keyword for targeting only a particular
+table in an inheritance hierarchy. This can be used to produce the
+``SELECT ... FROM ONLY``, ``UPDATE ONLY ...``, and ``DELETE FROM ONLY ...``
+syntaxes. It uses SQLAlchemy's hints mechanism:
+
+    # SELECT ... FROM ONLY ...
+    result = table.select().with_hint(table, 'ONLY', 'postgresql')
+    print result.fetchall()
+
+    # UPDATE ONLY ...
+    table.update(values=dict(foo='bar')).with_hint('ONLY',
+                                                   dialect_name='postgresql')
+
+    # DELETE FROM ONLY ...
+    table.delete().with_hint('ONLY', dialect_name='postgresql')
 
 .. _postgresql_indexes:
 
             text += " OFFSET " + self.process(sql.literal(select._offset))
         return text
 
+    def format_from_hint_text(self, sqltext, table, hint, iscrud):
+        if hint.upper() != 'ONLY':
+            raise exc.CompileError("Unrecognized hint: %r" % hint)
+        return "ONLY " + sqltext
+
     def get_select_precolumns(self, select):
         if select._distinct is not False:
             if select._distinct is True:

File lib/sqlalchemy/dialects/sybase/pysybase.py

 
 
 class SybaseSQLCompiler_pysybase(SybaseSQLCompiler):
-    def bindparam_string(self, name):
+    def bindparam_string(self, name, **kw):
         return "@" + name
 
 class SybaseDialect_pysybase(SybaseDialect):

File lib/sqlalchemy/engine/base.py

 
 
             if is_disconnect:
+                dbapi_conn_wrapper = self.connection
                 self.invalidate(e)
-                self.engine.dispose()
+                if not hasattr(dbapi_conn_wrapper, '_pool') or \
+                    dbapi_conn_wrapper._pool is self.engine.pool:
+                    self.engine.dispose()
             else:
                 if cursor:
                     self._safe_close_cursor(cursor)
         the engine are not affected. 
 
         """
-        self.pool.dispose()
-        self.pool = self.pool.recreate()
+        self.pool = self.pool._replace()
 
     @util.deprecated("0.7", "Use the create() method on the given schema "
                             "object directly, i.e. :meth:`.Table.create`, "

File lib/sqlalchemy/event.py

 
 """Base event API."""
 
-from sqlalchemy import util, exc
+from . import util, exc
 
 CANCEL = util.symbol('CANCEL')
 NO_RETVAL = util.symbol('NO_RETVAL')
             object."""
 
         for ls in _event_descriptors(other):
-            getattr(self, ls.name)._update(ls, only_propagate=only_propagate)
+            getattr(self, ls.name).\
+                for_modify(self)._update(ls, only_propagate=only_propagate)
 
 def _event_descriptors(target):
     return [getattr(target, k) for k in dir(target) if _is_event_name(k)]
     @classmethod
     def _listen(cls, target, identifier, fn, propagate=False, insert=False):
         if insert:
-            getattr(target.dispatch, identifier).insert(fn, target, propagate)
+            getattr(target.dispatch, identifier).\
+                    for_modify(target.dispatch).insert(fn, target, propagate)
         else:
-            getattr(target.dispatch, identifier).append(fn, target, propagate)
+            getattr(target.dispatch, identifier).\
+                    for_modify(target.dispatch).append(fn, target, propagate)
 
     @classmethod
     def _remove(cls, target, identifier, fn):
         self.__name__ = fn.__name__
         self.__doc__ = fn.__doc__
         self._clslevel = util.defaultdict(list)
+        self._empty_listeners = {}
 
     def insert(self, obj, target, propagate):
         assert isinstance(target, type), \
         for dispatcher in self._clslevel.values():
             dispatcher[:] = []
 
+    def for_modify(self, obj):
+        """Return an event collection which can be modified.
+
+        For _DispatchDescriptor at the class level of
+        a dispatcher, this returns self.
+
+        """
+        return self
+
     def __get__(self, obj, cls):
         if obj is None:
             return self
-        obj.__dict__[self.__name__] = result = \
-                            _ListenerCollection(self, obj._parent_cls)
+        elif obj._parent_cls in self._empty_listeners:
+            ret = self._empty_listeners[obj._parent_cls]
+        else:
+            self._empty_listeners[obj._parent_cls] = ret = \
+                _EmptyListener(self, obj._parent_cls)
+        # assigning it to __dict__ means
+        # memoized for fast re-access.  but more memory.
+        obj.__dict__[self.__name__] = ret
+        return ret
+
+class _EmptyListener(object):
+    """Serves as a class-level interface to the events
+    served by a _DispatchDescriptor, when there are no 
+    instance-level events present.
+
+    Is replaced by _ListenerCollection when instance-level
+    events are added.
+
+    """
+    def __init__(self, parent, target_cls):
+        if target_cls not in parent._clslevel:
+            parent.update_subclass(target_cls)
+        self.parent = parent
+        self.parent_listeners = parent._clslevel[target_cls]
+        self.name = parent.__name__
+        self.propagate = frozenset()
+        self.listeners = ()
+
+    def for_modify(self, obj):
+        """Return an event collection which can be modified.
+
+        For _EmptyListener at the instance level of
+        a dispatcher, this generates a new 
+        _ListenerCollection, applies it to the instance,
+        and returns it.
+
+        """
+        obj.__dict__[self.name] = result = _ListenerCollection(
+                                        self.parent, obj._parent_cls)
         return result
 
+    def _needs_modify(self, *args, **kw):
+        raise NotImplementedError("need to call for_modify()")
+
+    exec_once = insert = append = remove = clear = _needs_modify
+
+    def __call__(self, *args, **kw):
+        """Execute this event."""
+
+        for fn in self.parent_listeners:
+            fn(*args, **kw)
+
+    def __len__(self):
+        return len(self.parent_listeners)
+
+    def __iter__(self):
+        return iter(self.parent_listeners)
+
+    def __getitem__(self, index):
+        return (self.parent_listeners)[index]
+
+    def __nonzero__(self):
+        return bool(self.listeners)
+
+
 class _ListenerCollection(object):
     """Instance-level attributes on instances of :class:`._Dispatch`.
 
     Represents a collection of listeners.
 
+    As of 0.7.9, _ListenerCollection is only first
+    created via the _EmptyListener.for_modify() method.
+
     """
 
     _exec_once = False
         self.listeners = []
         self.propagate = set()
 
+    def for_modify(self, obj):
+        """Return an event collection which can be modified.
+
+        For _ListenerCollection at the instance level of
+        a dispatcher, this returns self.
+
+        """
+        return self
+
     def exec_once(self, *args, **kw):
         """Execute this event, but only if it has not been
         executed already for this collection."""
     # I'm not entirely thrilled about the overhead here,
     # but this allows class-level listeners to be added
     # at any point.
-    #
-    # alternatively, _DispatchDescriptor could notify
-    # all _ListenerCollection objects, but then we move
-    # to a higher memory model, i.e.weakrefs to all _ListenerCollection
-    # objects, the _DispatchDescriptor collection repeated
-    # for all instances.
+    # 
+    # In the absense of instance-level listeners,
+    # we stay with the _EmptyListener object when called
+    # at the instance level.
 
     def __len__(self):
         return len(self.parent_listeners + self.listeners)

File lib/sqlalchemy/events.py

 
 """Core event interfaces."""
 
-from sqlalchemy import event, exc, util
+from . import event, exc, util
 engine = util.importlater('sqlalchemy', 'engine')
 pool = util.importlater('sqlalchemy', 'pool')
 

File lib/sqlalchemy/ext/declarative.py

 
 Note that above, the ``Engineer.id`` attribute, since it shares the
 same attribute name as the ``Person.id`` attribute, will in fact
-represent the ``people.id`` and ``engineers.id`` columns together, and
-will render inside a query as ``"people.id"``. 
+represent the ``people.id`` and ``engineers.id`` columns together,
+with the "Engineer.id" column taking precedence if queried directly.
 To provide the ``Engineer`` class with an attribute that represents
 only the ``engineers.id`` column, give it a different attribute name::
 
                                                     primary_key=True)
         primary_language = Column(String(50))
 
+
+.. versionchanged:: 0.7 joined table inheritance favors the subclass
+   column over that of the superclass, such as querying above
+   for ``Engineer.id``.  Prior to 0.7 this was the reverse.
+   
 Single Table Inheritance
 ~~~~~~~~~~~~~~~~~~~~~~~~
 

File lib/sqlalchemy/ext/instrumentation.py

+"""Extensible class instrumentation.
+
+The :mod:`sqlalchemy.ext.instrumentation` package provides for alternate
+systems of class instrumentation within the ORM.  Class instrumentation
+refers to how the ORM places attributes on the class which maintain 
+data and track changes to that data, as well as event hooks installed
+on the class.
+
+.. note::
+    The extension package is provided for the benefit of integration
+    with other object management packages, which already perform
+    their own instrumentation.  It is not intended for general use.
+
+For examples of how the instrumentation extension is used, 
+see the example :ref:`examples_instrumentation`.
+
+.. versionchanged:: 0.8
+   The :mod:`sqlalchemy.orm.instrumentation` was split out so 
+   that all functionality having to do with non-standard
+   instrumentation was moved out to :mod:`sqlalchemy.ext.instrumentation`.
+   When imported, the module installs itself within
+   :mod:`sqlalchemy.orm.instrumentation` so that it
+   takes effect, including recognition of 
+   ``__sa_instrumentation_manager__`` on mapped classes, as 
+   well :attr:`.instrumentation_finders` 
+   being used to determine class instrumentation resolution.
+   
+"""
+from ..orm import instrumentation as orm_instrumentation
+from ..orm.instrumentation import (
+    ClassManager, InstrumentationFactory, _default_state_getter, 
+    _default_dict_getter, _default_manager_getter
+)
+from ..orm import attributes, collections
+from .. import util
+from ..orm import exc as orm_exc
+import weakref
+
+INSTRUMENTATION_MANAGER = '__sa_instrumentation_manager__'
+"""Attribute, elects custom instrumentation when present on a mapped class.
+
+Allows a class to specify a slightly or wildly different technique for
+tracking changes made to mapped attributes and collections.
+
+Only one instrumentation implementation is allowed in a given object
+inheritance hierarchy.
+
+The value of this attribute must be a callable and will be passed a class
+object.  The callable must return one of:
+
+  - An instance of an InstrumentationManager or subclass
+  - An object implementing all or some of InstrumentationManager (TODO)
+  - A dictionary of callables, implementing all or some of the above (TODO)
+  - An instance of a ClassManager or subclass
+
+This attribute is consulted by SQLAlchemy instrumentation
+resolution, once the :mod:`sqlalchemy.ext.instrumentation` module
+has been imported.  If custom finders are installed in the global
+instrumentation_finders list, they may or may not choose to honor this
+attribute.
+
+"""
+
+def find_native_user_instrumentation_hook(cls):
+    """Find user-specified instrumentation management for a class."""
+    return getattr(cls, INSTRUMENTATION_MANAGER, None)
+
+instrumentation_finders = [find_native_user_instrumentation_hook]
+"""An extensible sequence of callables which return instrumentation implementations
+
+When a class is registered, each callable will be passed a class object.  
+If None is returned, the
+next finder in the sequence is consulted.  Otherwise the return must be an
+instrumentation factory that follows the same guidelines as
+sqlalchemy.ext.instrumentation.INSTRUMENTATION_MANAGER.
+
+By default, the only finder is find_native_user_instrumentation_hook, which
+searches for INSTRUMENTATION_MANAGER.  If all finders return None, standard
+ClassManager instrumentation is used.
+
+"""
+
+class ExtendedInstrumentationRegistry(InstrumentationFactory):
+    """Extends :class:`.InstrumentationFactory` with additional
+    bookkeeping, to accommodate multiple types of 
+    class managers.
+    
+    """
+    _manager_finders = weakref.WeakKeyDictionary()
+    _state_finders = weakref.WeakKeyDictionary()
+    _dict_finders = weakref.WeakKeyDictionary()
+    _extended = False
+
+    def _locate_extended_factory(self, class_):
+        for finder in instrumentation_finders:
+            factory = finder(class_)
+            if factory is not None:
+                manager = self._extended_class_manager(class_, factory)
+                return manager, factory
+        else:
+            return None, None
+
+    def _check_conflicts(self, class_, factory):
+        existing_factories = self._collect_management_factories_for(class_).\
+                                difference([factory])
+        if existing_factories:
+            raise TypeError(
+                "multiple instrumentation implementations specified "
+                "in %s inheritance hierarchy: %r" % (
+                    class_.__name__, list(existing_factories)))
+
+    def _extended_class_manager(self, class_, factory):
+        manager = factory(class_)
+        if not isinstance(manager, ClassManager):
+            manager = _ClassInstrumentationAdapter(class_, manager)
+
+        if factory != ClassManager and not self._extended:
+            # somebody invoked a custom ClassManager.
+            # reinstall global "getter" functions with the more 
+            # expensive ones.
+            self._extended = True
+            _install_instrumented_lookups()
+
+        self._manager_finders[class_] = manager.manager_getter()
+        self._state_finders[class_] = manager.state_getter()
+        self._dict_finders[class_] = manager.dict_getter()
+        return manager
+
+    def _collect_management_factories_for(self, cls):
+        """Return a collection of factories in play or specified for a
+        hierarchy.
+
+        Traverses the entire inheritance graph of a cls and returns a
+        collection of instrumentation factories for those classes. Factories
+        are extracted from active ClassManagers, if available, otherwise
+        instrumentation_finders is consulted.
+
+        """
+        hierarchy = util.class_hierarchy(cls)
+        factories = set()
+        for member in hierarchy:
+            manager = self.manager_of_class(member)
+            if manager is not None:
+                factories.add(manager.factory)
+            else:
+                for finder in instrumentation_finders:
+                    factory = finder(member)
+                    if factory is not None:
+                        break
+                else:
+                    factory = None
+                factories.add(factory)
+        factories.discard(None)
+        return factories
+
+    def unregister(self, class_):
+        if class_ in self._manager_finders:
+            del self._manager_finders[class_]
+            del self._state_finders[class_]
+            del self._dict_finders[class_]
+        super(ExtendedInstrumentationRegistry, self).unregister(class_)
+
+    def manager_of_class(self, cls):
+        if cls is None:
+            return None
+        return self._manager_finders.get(cls, _default_manager_getter)(cls)
+
+    def state_of(self, instance):
+        if instance is None:
+            raise AttributeError("None has no persistent state.")
+        return self._state_finders.get(instance.__class__, _default_state_getter)(instance)
+
+    def dict_of(self, instance):
+        if instance is None:
+            raise AttributeError("None has no persistent state.")
+        return self._dict_finders.get(instance.__class__, _default_dict_getter)(instance)
+
+orm_instrumentation._instrumentation_factory = \
+        _instrumentation_factory = ExtendedInstrumentationRegistry()
+orm_instrumentation.instrumentation_finders = instrumentation_finders
+
+class InstrumentationManager(object):
+    """User-defined class instrumentation extension.
+
+    :class:`.InstrumentationManager` can be subclassed in order
+    to change
+    how class instrumentation proceeds. This class exists for
+    the purposes of integration with other object management
+    frameworks which would like to entirely modify the
+    instrumentation methodology of the ORM, and is not intended
+    for regular usage.  For interception of class instrumentation
+    events, see :class:`.InstrumentationEvents`.
+
+    The API for this class should be considered as semi-stable,
+    and may change slightly with new releases.
+
+    .. versionchanged:: 0.8
+       :class:`.InstrumentationManager` was moved from
+       :mod:`sqlalchemy.orm.instrumentation` to 
+       :mod:`sqlalchemy.ext.instrumentation`.   
+       
+    """
+
+    # r4361 added a mandatory (cls) constructor to this interface.
+    # given that, perhaps class_ should be dropped from all of these
+    # signatures.
+
+    def __init__(self, class_):
+        pass
+
+    def manage(self, class_, manager):
+        setattr(class_, '_default_class_manager', manager)
+
+    def dispose(self, class_, manager):
+        delattr(class_, '_default_class_manager')
+
+    def manager_getter(self, class_):
+        def get(cls):
+            return cls._default_class_manager
+        return get
+
+    def instrument_attribute(self, class_, key, inst):
+        pass
+
+    def post_configure_attribute(self, class_, key, inst):
+        pass
+
+    def install_descriptor(self, class_, key, inst):
+        setattr(class_, key, inst)
+
+    def uninstall_descriptor(self, class_, key):
+        delattr(class_, key)
+
+    def install_member(self, class_, key, implementation):
+        setattr(class_, key, implementation)
+
+    def uninstall_member(self, class_, key):
+        delattr(class_, key)
+
+    def instrument_collection_class(self, class_, key, collection_class):
+        return collections.prepare_instrumentation(collection_class)
+
+    def get_instance_dict(self, class_, instance):
+        return instance.__dict__
+
+    def initialize_instance_dict(self, class_, instance):
+        pass
+
+    def install_state(self, class_, instance, state):
+        setattr(instance, '_default_state', state)
+
+    def remove_state(self, class_, instance):
+        delattr(instance, '_default_state')
+
+    def state_getter(self, class_):
+        return lambda instance: getattr(instance, '_default_state')
+
+    def dict_getter(self, class_):
+        return lambda inst: self.get_instance_dict(class_, inst)
+
+class _ClassInstrumentationAdapter(ClassManager):
+    """Adapts a user-defined InstrumentationManager to a ClassManager."""
+
+    def __init__(self, class_, override):
+        self._adapted = override
+        self._get_state = self._adapted.state_getter(class_)
+        self._get_dict = self._adapted.dict_getter(class_)
+
+        ClassManager.__init__(self, class_)
+
+    def manage(self):
+        self._adapted.manage(self.class_, self)
+
+    def dispose(self):
+        self._adapted.dispose(self.class_)
+
+    def manager_getter(self):
+        return self._adapted.manager_getter(self.class_)
+
+    def instrument_attribute(self, key, inst, propagated=False):
+        ClassManager.instrument_attribute(self, key, inst, propagated)
+        if not propagated:
+            self._adapted.instrument_attribute(self.class_, key, inst)
+
+    def post_configure_attribute(self, key):
+        super(_ClassInstrumentationAdapter, self).post_configure_attribute(key)
+        self._adapted.post_configure_attribute(self.class_, key, self[key])
+
+    def install_descriptor(self, key, inst):
+        self._adapted.install_descriptor(self.class_, key, inst)
+
+    def uninstall_descriptor(self, key):
+        self._adapted.uninstall_descriptor(self.class_, key)
+
+    def install_member(self, key, implementation):
+        self._adapted.install_member(self.class_, key, implementation)
+
+    def uninstall_member(self, key):
+        self._adapted.uninstall_member(self.class_, key)
+
+    def instrument_collection_class(self, key, collection_class):
+        return self._adapted.instrument_collection_class(
+            self.class_, key, collection_class)
+
+    def initialize_collection(self, key, state, factory):
+        delegate = getattr(self._adapted, 'initialize_collection', None)
+        if delegate:
+            return delegate(key, state, factory)
+        else:
+            return ClassManager.initialize_collection(self, key, 
+                                                        state, factory)
+
+    def new_instance(self, state=None):
+        instance = self.class_.__new__(self.class_)
+        self.setup_instance(instance, state)
+        return instance
+
+    def _new_state_if_none(self, instance):
+        """Install a default InstanceState if none is present.
+
+        A private convenience method used by the __init__ decorator.
+        """
+        if self.has_state(instance):
+            return False
+        else:
+            return self.setup_instance(instance)
+
+    def setup_instance(self, instance, state=None):
+        self._adapted.initialize_instance_dict(self.class_, instance)
+
+        if state is None:
+            state = self._state_constructor(instance, self)
+
+        # the given instance is assumed to have no state
+        self._adapted.install_state(self.class_, instance, state)
+        return state
+
+    def teardown_instance(self, instance):
+        self._adapted.remove_state(self.class_, instance)
+
+    def has_state(self, instance):
+        try:
+            state = self._get_state(instance)
+        except orm_exc.NO_STATE:
+            return False
+        else:
+            return True
+
+    def state_getter(self):
+        return self._get_state
+
+    def dict_getter(self):
+        return self._get_dict
+
+def _install_instrumented_lookups():
+    """Replace global class/object management functions
+    with ExtendedInstrumentationRegistry implementations, which
+    allow multiple types of class managers to be present,
+    at the cost of performance.
+
+    This function is called only by ExtendedInstrumentationRegistry
+    and unit tests specific to this behavior.
+
+    The _reinstall_default_lookups() function can be called
+    after this one to re-establish the default functions.
+
+    """
+    _install_lookups(
+        dict(
+            instance_state = _instrumentation_factory.state_of,
+            instance_dict = _instrumentation_factory.dict_of,
+            manager_of_class = _instrumentation_factory.manager_of_class
+        )
+    )
+
+def _reinstall_default_lookups():
+    """Restore simplified lookups."""
+    _install_lookups(
+        dict(
+            instance_state = _default_state_getter,
+            instance_dict = _default_dict_getter,
+            manager_of_class = _default_manager_getter
+        )
+    )
+
+def _install_lookups(lookups):
+    global instance_state, instance_dict, manager_of_class
+    instance_state = lookups['instance_state']
+    instance_dict = lookups['instance_dict']
+    manager_of_class = lookups['manager_of_class']
+    attributes.instance_state = \
+        orm_instrumentation.instance_state = instance_state
+    attributes.instance_dict = \
+        orm_instrumentation.instance_dict = instance_dict
+    attributes.manager_of_class = \
+        orm_instrumentation.manager_of_class = manager_of_class

File lib/sqlalchemy/inspection.py

 of argument.
 """
 
-from sqlalchemy import util
+from . import util
 _registrars = util.defaultdict(list)
 
 def inspect(subject):

File lib/sqlalchemy/interfaces.py

 
 """
 
-from sqlalchemy import event, util
+from . import event, util
 
 class PoolListener(object):
     """Hooks into the lifecycle of connections in a :class:`.Pool`.

File lib/sqlalchemy/log.py

 
 import logging
 import sys
-from sqlalchemy import util
+from . import util
 
 # set initial level to WARN.  This so that
 # log statements don't occur in the absense of explicit