Commits

Mike Bayer committed ea64051

- document the inspection system

Comments (0)

Files changed (15)

doc/build/core/index.rst

     event
     events
     compiler
+    inspection
     serializer
     interfaces
     exceptions

doc/build/core/inspection.rst

+.. _core_inspection_toplevel:
+
+Runtime Inpection API
+=====================
+
+.. automodule:: sqlalchemy.inspection
+    :members:
+
+Available Inspection Targets
+----------------------------
+
+Following is a listing of all inspection targets.
+
+* :class:`.Connectable` (i.e. :class:`.Engine`,
+  :class:`.Connection`) - returns an :class:`.Inspector` object.
+* :class:`.ClauseElement` - all SQL expression components, including
+  :class:`.Table`, :class:`.Column`, serve as their own inspection objects,
+  meaning any of these objects passed to :func:`.inspect` return themselves.
+* ``object`` - an object given will be checked by the ORM for a mapping -
+  if so, an :class:`.InstanceState` is returned representing the mapped
+  state of the object.
+* ``type`` (i.e. a class) - a class given will be checked by the ORM for a
+  mapping - if so, a :class:`.Mapper` for that class is returned.
+* mapped attribute - passing a mapped attribute to :func:`.inspect`, such
+  as ``inspect(MyClass.some_attribute)``, returns a :class:`.MapperProperty`
+  object, which usually is an instance of :class:`.ColumnProperty`
+  or :class:`.RelationshipProperty`.
+* :class:`.AliasedClass` - returns an :class:`.AliasedInsp` object.
+

doc/build/index.rst

 
 A high level view and getting set up.
 
-:ref:`Overview <overview>` | 
+:ref:`Overview <overview>` |
 :ref:`Installation Guide <installation>` |
 :ref:`Migration from 0.7 <migration>`
 
 ===============
 
 The breadth of SQLAlchemy's SQL rendering engine, DBAPI
-integration, transaction integration, and schema description services 
+integration, transaction integration, and schema description services
 are documented here.  In contrast to the ORM's domain-centric mode of usage, the SQL Expression Language provides a schema-centric usage paradigm.
 
 * **Read this first:**
   :ref:`Database Introspection (Reflection) <metadata_reflection>` |
   :ref:`Insert/Update Defaults <metadata_defaults>` |
   :ref:`Constraints and Indexes <metadata_constraints>` |
-  :ref:`Using Data Definition Language (DDL) <metadata_ddl>` 
+  :ref:`Using Data Definition Language (DDL) <metadata_ddl>`
 
 * **Datatypes:**
-  :ref:`Overview <types_toplevel>` | 
-  :ref:`Generic Types <types_generic>` | 
+  :ref:`Overview <types_toplevel>` |
+  :ref:`Generic Types <types_generic>` |
   :ref:`SQL Standard Types <types_sqlstandard>` |
   :ref:`Vendor Specific Types <types_vendor>` |
   :ref:`Building Custom Types <types_custom>` |
-  :ref:`API <types_api>` 
+  :ref:`API <types_api>`
 
 * **Extending the Core:**
   :doc:`SQLAlchemy Events <core/event>` |
   :doc:`Internals API <core/internals>`
 
 * **Other:**
+  :doc:`Runtime Inspection API <core/inspection>` |
   :doc:`Serializing Expressions <core/serializer>` |
   :doc:`core/interfaces` |
   :doc:`core/exceptions`

doc/build/orm/internals.rst

     :members:
     :show-inheritance:
 
+.. autoclass:: sqlalchemy.orm.state.InspectAttr
+    :members:
+    :show-inheritance:
+
 .. autoclass:: sqlalchemy.orm.interfaces.MapperProperty
     :members:
     :show-inheritance:

doc/build/orm/mapper_config.rst

     mapper(User, user)
 
 Information about mapped attributes, such as relationships to other classes, are provided
-via the ``properties`` dictionary.  The example below illustrates a second :class:`.Table` 
+via the ``properties`` dictionary.  The example below illustrates a second :class:`.Table`
 object, mapped to a class called ``Address``, then linked to ``User`` via :func:`.relationship`::
 
     address = Table('address', metadata,
 yet be linked to table metadata, nor can we specify a string here.
 
 Some examples in the documentation still use the classical approach, but note that
-the classical as well as Declarative approaches are **fully interchangeable**.  Both 
-systems ultimately create the same configuration, consisting of a :class:`.Table`, 
+the classical as well as Declarative approaches are **fully interchangeable**.  Both
+systems ultimately create the same configuration, consisting of a :class:`.Table`,
 user-defined class, linked together with a :func:`.mapper`.  When we talk about
 "the behavior of :func:`.mapper`", this includes when using the Declarative system
 as well - it's still used, just behind the scenes.
 Naming All Columns with a Prefix
 --------------------------------
 
-A way to automate the assignment of a prefix to 
+A way to automate the assignment of a prefix to
 the mapped attribute names relative to the column name
 is to use ``column_prefix``::
 
         id = Column(Integer, primary_key=True)
         name = column_property(Column(String(50)), active_history=True)
 
-:func:`.column_property` is also used to map a single attribute to 
+:func:`.column_property` is also used to map a single attribute to
 multiple columns.  This use case arises when mapping to a :func:`~.expression.join`
 which has attributes which are equated to each other::
 
 
 For more examples featuring this usage, see :ref:`maptojoin`.
 
-Another place where :func:`.column_property` is needed is to specify SQL expressions as 
+Another place where :func:`.column_property` is needed is to specify SQL expressions as
 mapped attributes, such as below where we create an attribute ``fullname``
 that is the string concatenation of the ``firstname`` and ``lastname``
 columns::
 Mapping a Subset of Table Columns
 ---------------------------------
 
-Sometimes, a :class:`.Table` object was made available using the 
-reflection process described at :ref:`metadata_reflection` to load 
+Sometimes, a :class:`.Table` object was made available using the
+reflection process described at :ref:`metadata_reflection` to load
 the table's structure from the database.
 For such a table that has lots of columns that don't need to be referenced
-in the application, the ``include_properties`` or ``exclude_properties`` 
+in the application, the ``include_properties`` or ``exclude_properties``
 arguments can specify that only a subset of columns should be mapped.
 For example::
 
             'primary_key' : [user_table.c.id]
         }
 
-.. note:: 
+.. note::
 
    insert and update defaults configured on individual
    :class:`.Column` objects, i.e. those described at :ref:`metadata_defaults`
 ========================
 
 This feature allows particular columns of a table be loaded only
-upon direct access, instead of when the entity is queried using 
+upon direct access, instead of when the entity is queried using
 :class:`.Query`.  This feature is useful when one wants to avoid
 loading a large text or binary field into memory when it's not needed.
 Individual columns can be lazy loaded by themselves or placed into groups that
-lazy-load together, using the :func:`.orm.deferred` function to 
+lazy-load together, using the :func:`.orm.deferred` function to
 mark them as "deferred". In the example below, we define a mapping that will load each of
 ``.excerpt`` and ``.photo`` in separate, individual-row SELECT statements when each
 attribute is first referenced on the individual object instance::
 SQL Expressions as Mapped Attributes
 =====================================
 
-Attributes on a mapped class can be linked to SQL expressions, which can 
-be used in queries. 
+Attributes on a mapped class can be linked to SQL expressions, which can
+be used in queries.
 
 Using a Hybrid
 --------------
 The easiest and most flexible way to link relatively simple SQL expressions to a class is to use a so-called
 "hybrid attribute",
 described in the section :ref:`hybrids_toplevel`.  The hybrid provides
-for an expression that works at both the Python level as well as at the 
+for an expression that works at both the Python level as well as at the
 SQL expression level.  For example, below we map a class ``User``,
 containing attributes ``firstname`` and ``lastname``, and include a hybrid that
 will provide for us the ``fullname``, which is the string concatenation of the two::
         def fullname(self):
             return self.firstname + " " + self.lastname
 
-Above, the ``fullname`` attribute is interpreted at both the instance and 
+Above, the ``fullname`` attribute is interpreted at both the instance and
 class level, so that it is available from an instance::
 
     some_user = session.query(User).first()
 ---------------------
 
 The :func:`.orm.column_property` function can be used to map a SQL
-expression in a manner similar to a regularly mapped :class:`.Column`.   
+expression in a manner similar to a regularly mapped :class:`.Column`.
 With this technique, the attribute is loaded
 along with all other column-mapped attributes at load time.  This is in some
 cases an advantage over the usage of hybrids, as the value can be loaded
 up front at the same time as the parent row of the object, particularly if
 the expression is one which links to other tables (typically as a correlated
-subquery) to access data that wouldn't normally be 
+subquery) to access data that wouldn't normally be
 available on an already loaded object.
 
-Disadvantages to using :func:`.orm.column_property` for SQL expressions include that 
-the expression must be compatible with the SELECT statement emitted for the class 
-as a whole, and there are also some configurational quirks which can occur 
+Disadvantages to using :func:`.orm.column_property` for SQL expressions include that
+the expression must be compatible with the SELECT statement emitted for the class
+as a whole, and there are also some configurational quirks which can occur
 when using :func:`.orm.column_property` from declarative mixins.
 
-Our "fullname" example can be expressed using :func:`.orm.column_property` as 
+Our "fullname" example can be expressed using :func:`.orm.column_property` as
 follows::
 
     from sqlalchemy.orm import column_property
     User.address_count = column_property(
             select([func.count(Address.id)]).\
                 where(Address.user_id==User.id)
-        ) 
+        )
 
 For many-to-many relationships, use :func:`.and_` to join the fields of the
 association table to both tables in a relation, illustrated
 
     mapper(Author, authors, properties={
         'book_count': column_property(
-                            select([func.count(books.c.id)], 
+                            select([func.count(books.c.id)],
                                 and_(
                                     book_authors.c.author_id==authors.c.id,
                                     book_authors.c.book_id==books.c.id
 -------------------------
 
 In cases where a SQL query more elaborate than what :func:`.orm.column_property`
-or :class:`.hybrid_property` can provide must be emitted, a regular Python 
+or :class:`.hybrid_property` can provide must be emitted, a regular Python
 function accessed as an attribute can be used, assuming the expression
-only needs to be available on an already-loaded instance.   The function 
+only needs to be available on an already-loaded instance.   The function
 is decorated with Python's own ``@property`` decorator to mark it as a read-only
 attribute.   Within the function, :func:`.object_session`
 is used to locate the :class:`.Session` corresponding to the current object,
             assert '@' in address.email
             return address
 
-Note that the :func:`~.validates` decorator is a convenience function built on 
+Note that the :func:`~.validates` decorator is a convenience function built on
 top of attribute events.   An application that requires more control over
 configuration of attribute change behavior can make use of this system,
 described at :class:`~.AttributeEvents`.
     {sql}address = session.query(EmailAddress).\
                      filter(EmailAddress.email == 'address@example.com').\
                      one()
-    SELECT address.email AS address_email, address.id AS address_id 
-    FROM address 
+    SELECT address.email AS address_email, address.id AS address_id
+    FROM address
     WHERE address.email = ?
     ('address@example.com',)
     {stop}
 
         @hybrid_property
         def email(self):
-            """Return the value of _email up until the last twelve 
+            """Return the value of _email up until the last twelve
             characters."""
 
             return self._email[:-12]
 
         @email.setter
         def email(self, email):
-            """Set the value of _email, tacking on the twelve character 
+            """Set the value of _email, tacking on the twelve character
             value @example.com."""
 
             self._email = email + "@example.com"
 
         @email.expression
         def email(cls):
-            """Produce a SQL expression that represents the value 
+            """Produce a SQL expression that represents the value
             of the _email column, minus the last twelve characters."""
 
             return func.substr(cls._email, 0, func.length(cls._email) - 12)
 .. sourcecode:: python+sql
 
     {sql}address = session.query(EmailAddress).filter(EmailAddress.email == 'address').one()
-    SELECT address.email AS address_email, address.id AS address_id 
-    FROM address 
+    SELECT address.email AS address_email, address.id AS address_id
+    FROM address
     WHERE substr(address.email, ?, length(address.email) - ?) = ?
     (0, 12, 'address')
     {stop}
 
 The expressions returned by comparison operations, such as
 ``User.name=='ed'``, can be customized, by implementing an object that
-explicitly defines each comparison method needed. 
+explicitly defines each comparison method needed.
 
-This is a relatively rare use case which generally applies only to 
-highly customized types.  Usually, custom SQL behaviors can be 
+This is a relatively rare use case which generally applies only to
+highly customized types.  Usually, custom SQL behaviors can be
 associated with a mapped class by composing together the classes'
-existing mapped attributes with other expression components, 
-using the techniques described in :ref:`mapper_sql_expressions`.  
+existing mapped attributes with other expression components,
+using the techniques described in :ref:`mapper_sql_expressions`.
 Those approaches should be considered first before resorting to custom comparison objects.
 
 Each of :func:`.orm.column_property`, :func:`~.composite`, :func:`.relationship`,
 and :func:`.comparable_property` accept an argument called
 ``comparator_factory``.   A subclass of :class:`.PropComparator` can be provided
 for this argument, which can then reimplement basic Python comparison methods
-such as ``__eq__()``, ``__ne__()``, ``__lt__()``, and so on. 
+such as ``__eq__()``, ``__ne__()``, ``__lt__()``, and so on.
 
 It's best to subclass the :class:`.PropComparator` subclass provided by
 each type of property.  For example, to allow a column-mapped attribute to
     lower(address.email) = lower(:lower_1)
 
 When building a :class:`.PropComparator`, the ``__clause_element__()`` method
-should be used in order to acquire the underlying mapped column.  This will 
+should be used in order to acquire the underlying mapped column.  This will
 return a column that is appropriately wrapped in any kind of subquery
 or aliasing that has been applied in the context of the generated SQL statement.
 
 class you provide.
 
 .. versionchanged:: 0.7
-    Composites have been simplified such that 
+    Composites have been simplified such that
     they no longer "conceal" the underlying column based attributes.  Additionally,
     in-place mutation is no longer automatic; see the section below on
     enabling mutability to support tracking of in-place changes.
     BEGIN (implicit)
     INSERT INTO vertice (x1, y1, x2, y2) VALUES (?, ?, ?, ?)
     (3, 4, 5, 6)
-    SELECT vertice.id AS vertice_id, 
-            vertice.x1 AS vertice_x1, 
-            vertice.y1 AS vertice_y1, 
-            vertice.x2 AS vertice_x2, 
-            vertice.y2 AS vertice_y2 
-    FROM vertice 
+    SELECT vertice.id AS vertice_id,
+            vertice.x1 AS vertice_x1,
+            vertice.y1 AS vertice_y1,
+            vertice.x2 AS vertice_x2,
+            vertice.y2 AS vertice_y2
+    FROM vertice
     WHERE vertice.x1 = ? AND vertice.y1 = ?
      LIMIT ? OFFSET ?
     (3, 4, 1, 0)
 Tracking In-Place Mutations on Composites
 -----------------------------------------
 
-In-place changes to an existing composite value are 
+In-place changes to an existing composite value are
 not tracked automatically.  Instead, the composite class needs to provide
-events to its parent object explicitly.   This task is largely automated 
+events to its parent object explicitly.   This task is largely automated
 via the usage of the :class:`.MutableComposite` mixin, which uses events
 to associate each user-defined composite object with all parent associations.
 Please see the example in :ref:`mutable_composites`.
 The "equals" comparison operation by default produces an AND of all
 corresponding columns equated to one another. This can be changed using
 the ``comparator_factory``, described in :ref:`custom_comparators`.
-Below we illustrate the "greater than" operator, implementing 
+Below we illustrate the "greater than" operator, implementing
 the same expression that the base "greater than" does::
 
     from sqlalchemy.orm.properties import CompositeProperty
         x2 = Column(Integer)
         y2 = Column(Integer)
 
-        start = composite(Point, x1, y1, 
+        start = composite(Point, x1, y1,
                             comparator_factory=PointComparator)
-        end = composite(Point, x2, y2, 
+        end = composite(Point, x2, y2,
                             comparator_factory=PointComparator)
 
 .. _maptojoin:
 ``user`` and the ``address`` table.  The ``user.id`` and ``address.user_id``
 columns are equated by foreign key, so in the mapping they are defined
 as one attribute, ``AddressUser.id``, using :func:`.column_property` to
-indicate a specialized column mapping.   Based on this part of the 
+indicate a specialized column mapping.   Based on this part of the
 configuration, the mapping will copy
 new primary key values from ``user.id`` into the ``address.user_id`` column
 when a flush occurs.
 
-Additionally, the ``address.id`` column is mapped explicitly to 
-an attribute named ``address_id``.   This is to **disambiguate** the 
-mapping of the ``address.id`` column from the same-named ``AddressUser.id`` 
+Additionally, the ``address.id`` column is mapped explicitly to
+an attribute named ``address_id``.   This is to **disambiguate** the
+mapping of the ``address.id`` column from the same-named ``AddressUser.id``
 attribute, which here has been assigned to refer to the ``user`` table
 combined with the ``address.user_id`` foreign key.
 
 The natural primary key of the above mapping is the composite of
 ``(user.id, address.id)``, as these are the primary key columns of the
-``user`` and ``address`` table combined together.  The identity of an 
+``user`` and ``address`` table combined together.  The identity of an
 ``AddressUser`` object will be in terms of these two values, and
-is represented from an ``AddressUser`` object as 
+is represented from an ``AddressUser`` object as
 ``(AddressUser.id, AddressUser.address_id)``.
 
 
 
 Similar to mapping against a join, a plain :func:`~.expression.select` object can be used with a
 mapper as well.  The example fragment below illustrates mapping a class
-called ``Customer`` to a :func:`~.expression.select` which includes a join to a 
+called ``Customer`` to a :func:`~.expression.select` which includes a join to a
 subquery::
 
     from sqlalchemy import select, func
 
     subq = select([
-                func.count(orders.c.id).label('order_count'), 
-                func.max(orders.c.price).label('highest_order'), 
+                func.count(orders.c.id).label('order_count'),
+                func.max(orders.c.price).label('highest_order'),
                 orders.c.customer_id
                 ]).group_by(orders.c.customer_id).alias()
 
 
 Above, the full row represented by ``customer_select`` will be all the
 columns of the ``customers`` table, in addition to those columns
-exposed by the ``subq`` subquery, which are ``order_count``, 
+exposed by the ``subq`` subquery, which are ``order_count``,
 ``highest_order``, and ``customer_id``.  Mapping the ``Customer``
 class to this selectable then creates a class which will contain
 those attributes.
 
-When the ORM persists new instances of ``Customer``, only the 
+When the ORM persists new instances of ``Customer``, only the
 ``customers`` table will actually receive an INSERT.  This is because the
 primary key of the ``orders`` table is not represented in the mapping;  the ORM
 will only emit an INSERT into a table for which it has mapped the primary
 attributes upon the class which are structured specifically according to the
 table metadata.
 
-One potential use case for another mapper to exist at the same time is if we 
+One potential use case for another mapper to exist at the same time is if we
 wanted to load instances of our class not just from the immediate :class:`.Table`
 to which it is mapped, but from another selectable that is a derivation of that
 :class:`.Table`.   While there technically is a way to create such a :func:`.mapper`,
 using the ``non_primary=True`` option, this approach is virtually never needed.
-Instead, we use the functionality of the :class:`.Query` object to achieve this, 
+Instead, we use the functionality of the :class:`.Query` object to achieve this,
 using a method such as :meth:`.Query.select_from`
 or :meth:`.Query.from_statement` to specify a derived selectable.
 
 Another potential use is if we genuinely want instances of our class to
-be persisted into different tables at different times; certain kinds of 
+be persisted into different tables at different times; certain kinds of
 data sharding configurations may persist a particular class into tables
-that are identical in structure except for their name.   For this kind of 
+that are identical in structure except for their name.   For this kind of
 pattern, Python offers a better approach than the complexity of mapping
 the same class multiple times, which is to instead create new mapped classes
 for each target table.    SQLAlchemy refers to this as the "entity name"
 conservative.
 
 :func:`~sqlalchemy.orm.reconstructor` is a shortcut into a larger system
-of "instance level" events, which can be subscribed to using the 
+of "instance level" events, which can be subscribed to using the
 event API - see :class:`.InstanceEvents` for the full API description
 of these events.
 
 
 .. autofunction:: class_mapper
 
-.. autofunction:: compile_mappers
-
 .. autofunction:: configure_mappers
 
 .. autofunction:: clear_mappers

doc/build/orm/query.rst

 
 .. autoclass:: sqlalchemy.orm.util.AliasedClass
 
+.. autoclass:: sqlalchemy.orm.util.AliasedInsp
+
 .. autofunction:: join
 
 .. autofunction:: outerjoin

doc/build/orm/session.rst

 are useful when constructing event listener functions, such as
 those described in :ref:`events_orm_toplevel`.
 
+.. currentmodule:: sqlalchemy.orm.util
+
+.. autofunction:: object_state
+
 .. currentmodule:: sqlalchemy.orm.attributes
 
 .. autofunction:: del_attribute
 
 .. function:: instance_state
 
-    Return the :class:`.InstanceState` for a given object.
+    Return the :class:`.InstanceState` for a given
+    mapped object.
+
+    This function is the internal version
+    of :func:`.object_state`.   The
+    :func:`.object_state` and/or the
+    :func:`.inspect` function is preferred here
+    as they each emit an informative exception
+    if the given object is not mapped.
 
 .. autofunction:: is_instrumented
 
-.. function:: manager_of_class
-
-    Return the :class:`.ClassManager` for a given class.
-
 .. autofunction:: set_attribute
 
 .. autofunction:: set_committed_value
 .. autoclass:: History
     :members:
 
-.. autodata:: PASSIVE_NO_INITIALIZE
-
-.. autodata:: PASSIVE_NO_FETCH
-
-.. autodata:: PASSIVE_NO_FETCH_RELATED
-
-.. autodata:: PASSIVE_ONLY_PERSISTENT
-
-.. autodata:: PASSIVE_OFF
-
-

lib/sqlalchemy/engine/reflection.py

     if info_cache is None:
         return fn(self, con, *args, **kw)
     key = (
-            fn.__name__, 
-            tuple(a for a in args if isinstance(a, basestring)), 
+            fn.__name__,
+            tuple(a for a in args if isinstance(a, basestring)),
             tuple((k, v) for k, v in kw.iteritems() if isinstance(v, (basestring, int, float)))
         )
     ret = info_cache.get(key)
     consistent interface as well as caching support for previously
     fetched metadata.
 
-    The preferred method to construct an :class:`.Inspector` is via the
-    :meth:`Inspector.from_engine` method.   I.e.::
+    A :class:`.Inspector` object is usually created via the
+    :func:`.inspect` function::
+
+        from sqlalchemy import inspect, create_engine
+        engine = create_engine('...')
+        insp = inspect(engine)
+
+    The inspection method above is equivalent to using the
+    :meth:`.Inspector.from_engine` method, i.e.::
 
         engine = create_engine('...')
         insp = Inspector.from_engine(engine)
     def __init__(self, bind):
         """Initialize a new :class:`.Inspector`.
 
-        :param bind: a :class:`~sqlalchemy.engine.base.Connectable`, 
-          which is typically an instance of 
-          :class:`~sqlalchemy.engine.base.Engine` or 
+        :param bind: a :class:`~sqlalchemy.engine.base.Connectable`,
+          which is typically an instance of
+          :class:`~sqlalchemy.engine.base.Engine` or
           :class:`~sqlalchemy.engine.base.Connection`.
 
         For a dialect-specific instance of :class:`.Inspector`, see
     def from_engine(cls, bind):
         """Construct a new dialect-specific Inspector object from the given engine or connection.
 
-        :param bind: a :class:`~sqlalchemy.engine.base.Connectable`, 
-          which is typically an instance of 
-          :class:`~sqlalchemy.engine.base.Engine` or 
+        :param bind: a :class:`~sqlalchemy.engine.base.Connectable`,
+          which is typically an instance of
+          :class:`~sqlalchemy.engine.base.Engine` or
           :class:`~sqlalchemy.engine.base.Connection`.
 
         This method differs from direct a direct constructor call of :class:`.Inspector`
     def reflecttable(self, table, include_columns, exclude_columns=()):
         """Given a Table object, load its internal constructs based on introspection.
 
-        This is the underlying method used by most dialects to produce 
+        This is the underlying method used by most dialects to produce
         table reflection.  Direct usage is like::
 
             from sqlalchemy import create_engine, MetaData, Table
         # Primary keys
         pk_cons = self.get_pk_constraint(table_name, schema, **tblkw)
         if pk_cons:
-            pk_cols = [table.c[pk] 
-                        for pk in pk_cons['constrained_columns'] 
+            pk_cols = [table.c[pk]
+                        for pk in pk_cons['constrained_columns']
                         if pk in table.c and pk not in exclude_columns
                     ] + [pk for pk in table.primary_key if pk.key in exclude_columns]
-            primary_key_constraint = sa_schema.PrimaryKeyConstraint(name=pk_cons.get('name'), 
+            primary_key_constraint = sa_schema.PrimaryKeyConstraint(name=pk_cons.get('name'),
                 *pk_cols
             )
 
             table.append_constraint(
                 sa_schema.ForeignKeyConstraint(constrained_columns, refspec,
                                                conname, link_to_name=True))
-        # Indexes 
+        # Indexes
         indexes = self.get_indexes(table_name, schema)
         for index_d in indexes:
             name = index_d['name']
                     "Omitting %s KEY for (%s), key covers omitted columns." %
                     (flavor, ', '.join(columns)))
                 continue
-            sa_schema.Index(name, *[table.columns[c] for c in columns], 
+            sa_schema.Index(name, *[table.columns[c] for c in columns],
                          **dict(unique=unique))

lib/sqlalchemy/exc.py

     """
 
 class NoInspectionAvailable(InvalidRequestError):
-    """A class to :func:`sqlalchemy.inspection.inspect` produced
+    """A subject passed to :func:`sqlalchemy.inspection.inspect` produced
     no context for inspection."""
 
 class ResourceClosedError(InvalidRequestError):

lib/sqlalchemy/inspection.py

 # This module is part of SQLAlchemy and is released under
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
-"""Base inspect API.
+"""The inspection module provides the :func:`.inspect` function,
+which delivers runtime information about a wide variety
+of SQLAlchemy objects, both within the Core as well as the
+ORM.
 
-:func:`.inspect` provides access to a contextual object
-regarding a subject.
+The :func:`.inspect` function is the entry point to SQLAlchemy's
+public API for viewing the configuration and construction
+of in-memory objects.   Depending on the type of object
+passed to :func:`.inspect`, the return value will either be
+a related object which provides a known interface, or in many
+cases it will return the object itself.
 
-Various subsections of SQLAlchemy,
-such as the :class:`.Inspector`, :class:`.Mapper`, and
-others register themselves with the "inspection registry" here
-so that they may return a context object given a certain kind
-of argument.
+The rationale for :func:`.inspect` is twofold.  One is that
+it replaces the need to be aware of a large variety of "information
+getting" functions in SQLAlchemy, such as :meth:`.Inspector.from_engine`,
+:func:`.orm.attributes.instance_state`, :func:`.orm.class_mapper`,
+and others.    The other is that the return value of :func:`.inspect`
+is guaranteed to obey a documented API, thus allowing third party
+tools which build on top of SQLAlchemy configurations to be constructed
+in a forwards-compatible way.
+
+.. versionadded:: 0.8 The :func:`.inspect` system is introduced
+   as of version 0.8.
+
 """
 
 from . import util, exc
 _registrars = util.defaultdict(list)
 
 def inspect(subject, raiseerr=True):
+    """Produce an inspection object for the given target.
+
+    The returned value in some cases may be the
+    same object as the one given, such as if a
+    :class:`.orm.Mapper` object is passed.   In other
+    cases, it will be an instance of the registered
+    inspection type for the given object, such as
+    if a :class:`.engine.Engine` is passed, an
+    :class:`.engine.Inspector` object is returned.
+
+    :param subject: the subject to be inspected.
+    :param raiseerr: When ``True``, if the given subject
+     does not
+     correspond to a known SQLAlchemy inspected type,
+     :class:`sqlalchemy.exc.NoInspectionAvailable`
+     is raised.  If ``False``, ``None`` is returned.
+
+     """
     type_ = type(subject)
     for cls in type_.__mro__:
         if cls in _registrars:

lib/sqlalchemy/orm/attributes.py

 """
 )
 
-NO_CHANGE = util.symbol("NO_CHANGE", 
+NO_CHANGE = util.symbol("NO_CHANGE",
 """No callables or SQL should be emitted on attribute access
 and no state should change""", canonical=0
 )
 )
 
 NON_PERSISTENT_OK = util.symbol("NON_PERSISTENT_OK",
-"""callables can be emitted if the parent is not persistent.""", 
+"""callables can be emitted if the parent is not persistent.""",
 canonical=16
 )
 
-
 # pre-packaged sets of flags used as inputs
-PASSIVE_OFF = RELATED_OBJECT_OK | \
-                NON_PERSISTENT_OK | \
-                INIT_OK | \
-                CALLABLES_OK | \
-                SQL_OK
-
-PASSIVE_RETURN_NEVER_SET = PASSIVE_OFF  ^ INIT_OK
-PASSIVE_NO_INITIALIZE = PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK
-PASSIVE_NO_FETCH = PASSIVE_OFF ^ SQL_OK
-PASSIVE_NO_FETCH_RELATED = PASSIVE_OFF ^ RELATED_OBJECT_OK
-PASSIVE_ONLY_PERSISTENT = PASSIVE_OFF ^ NON_PERSISTENT_OK
+PASSIVE_OFF = util.symbol("PASSIVE_OFF",
+    "Callables can be emitted in all cases.",
+    canonical=(RELATED_OBJECT_OK | NON_PERSISTENT_OK |
+                    INIT_OK | CALLABLES_OK | SQL_OK)
+)
+PASSIVE_RETURN_NEVER_SET = util.symbol("PASSIVE_RETURN_NEVER_SET",
+        """PASSIVE_OFF ^ INIT_OK""",
+        canonical=PASSIVE_OFF ^ INIT_OK
+)
+PASSIVE_NO_INITIALIZE = util.symbol("PASSIVE_NO_INITIALIZE",
+        "PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK",
+        canonical=PASSIVE_RETURN_NEVER_SET ^ CALLABLES_OK
+)
+PASSIVE_NO_FETCH = util.symbol("PASSIVE_NO_FETCH",
+        "PASSIVE_OFF ^ SQL_OK",
+        canonical=PASSIVE_OFF ^ SQL_OK
+)
+PASSIVE_NO_FETCH_RELATED = util.symbol("PASSIVE_NO_FETCH_RELATED",
+        "PASSIVE_OFF ^ RELATED_OBJECT_OK",
+        canonical=PASSIVE_OFF ^ RELATED_OBJECT_OK
+)
+PASSIVE_ONLY_PERSISTENT = util.symbol("PASSIVE_ONLY_PERSISTENT",
+        "PASSIVE_OFF ^ NON_PERSISTENT_OK",
+        canonical=PASSIVE_OFF ^ NON_PERSISTENT_OK
+)
 
 
 class QueryableAttribute(interfaces.PropComparator):
     """Base class for class-bound attributes. """
 
-    def __init__(self, class_, key, impl=None, 
+    def __init__(self, class_, key, impl=None,
                         comparator=None, parententity=None,
                         of_type=None):
         self.class_ = class_
         manager = manager_of_class(class_)
         # manager is None in the case of AliasedClass
         if manager:
-            # propagate existing event listeners from 
+            # propagate existing event listeners from
             # immediate superclass
             for base in manager._bases:
                 if key in base:
         except AttributeError:
             raise AttributeError(
                     'Neither %r object nor %r object has an attribute %r' % (
-                    type(self).__name__, 
-                    type(self.comparator).__name__, 
+                    type(self).__name__,
+                    type(self.comparator).__name__,
                     key)
             )
 
     """Class bound instrumented attribute which adds descriptor methods."""
 
     def __set__(self, instance, value):
-        self.impl.set(instance_state(instance), 
+        self.impl.set(instance_state(instance),
                         instance_dict(instance), value, None)
 
     def __delete__(self, instance):
 
     class Proxy(QueryableAttribute):
         """Presents the :class:`.QueryableAttribute` interface as a
-        proxy on top of a Python descriptor / :class:`.PropComparator` 
+        proxy on top of a Python descriptor / :class:`.PropComparator`
         combination.
 
         """
 
-        def __init__(self, class_, key, descriptor, 
-                                comparator, 
+        def __init__(self, class_, key, descriptor,
+                                comparator,
                                 adapter=None, doc=None,
                                 original_property=None):
             self.class_ = class_
                 except AttributeError:
                     raise AttributeError(
                     'Neither %r object nor %r object has an attribute %r' % (
-                    type(descriptor).__name__, 
-                    type(self.comparator).__name__, 
+                    type(descriptor).__name__,
+                    type(self.comparator).__name__,
                     attribute)
                     )
 
 
     def __init__(self, class_, key,
                     callable_, dispatch, trackparent=False, extension=None,
-                    compare_function=None, active_history=False, 
+                    compare_function=None, active_history=False,
                     parent_token=None, expire_missing=True,
                     **kwargs):
         """Construct an AttributeImpl.
         parent_token
           Usually references the MapperProperty, used as a key for
           the hasparent() function to identify an "owning" attribute.
-          Allows multiple AttributeImpls to all match a single 
+          Allows multiple AttributeImpls to all match a single
           owner attribute.
 
         expire_missing
           if False, don't add an "expiry" callable to this attribute
-          during state.expire_attributes(None), if no value is present 
+          during state.expire_attributes(None), if no value is present
           for this key.
 
         """
 
 
     def hasparent(self, state, optimistic=False):
-        """Return the boolean value of a `hasparent` flag attached to 
+        """Return the boolean value of a `hasparent` flag attached to
         the given state.
 
         The `optimistic` flag determines what the default return value
                             "state %s along attribute '%s', "
                             "but the parent record "
                             "has gone stale, can't be sure this "
-                            "is the most recent parent." % 
-                            (orm_util.state_str(state), 
+                            "is the most recent parent." %
+                            (orm_util.state_str(state),
                             orm_util.state_str(parent_state),
                             self.key))
 
         raise NotImplementedError()
 
     def get_all_pending(self, state, dict_):
-        """Return a list of tuples of (state, obj) 
-        for all objects in this attribute's current state 
+        """Return a list of tuples of (state, obj)
+        for all objects in this attribute's current state
         + history.
 
         Only applies to object-based attributes.
         which roughly corresponds to:
 
             get_state_history(
-                        state, 
-                        key, 
+                        state,
+                        key,
                         passive=PASSIVE_NO_INITIALIZE).sum()
 
         """
         self.set(state, dict_, value, initiator, passive=passive)
 
     def remove(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
-        self.set(state, dict_, None, initiator, 
+        self.set(state, dict_, None, initiator,
                     passive=passive, check_old=value)
 
     def pop(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
-        self.set(state, dict_, None, initiator, 
+        self.set(state, dict_, None, initiator,
                     passive=passive, check_old=value, pop=True)
 
-    def set(self, state, dict_, value, initiator, 
+    def set(self, state, dict_, value, initiator,
                 passive=PASSIVE_OFF, check_old=None, pop=False):
         raise NotImplementedError()
 
         return History.from_scalar_attribute(
             self, state, dict_.get(self.key, NO_VALUE))
 
-    def set(self, state, dict_, value, initiator, 
+    def set(self, state, dict_, value, initiator,
                 passive=PASSIVE_OFF, check_old=None, pop=False):
         if initiator and initiator.parent_token is self.parent_token:
             return
             old = dict_.get(self.key, NO_VALUE)
 
         if self.dispatch.set:
-            value = self.fire_replace_event(state, dict_, 
+            value = self.fire_replace_event(state, dict_,
                                                 value, old, initiator)
         state._modified_event(dict_, self, old)
         dict_[self.key] = value
 
 
 class ScalarObjectAttributeImpl(ScalarAttributeImpl):
-    """represents a scalar-holding InstrumentedAttribute, 
+    """represents a scalar-holding InstrumentedAttribute,
        where the target object is also instrumented.
 
        Adds events to delete/set operations.
         else:
             return []
 
-    def set(self, state, dict_, value, initiator, 
+    def set(self, state, dict_, value, initiator,
                 passive=PASSIVE_OFF, check_old=None, pop=False):
         """Set a value on the given InstanceState.
 
                     typecallable=None, trackparent=False, extension=None,
                     copy_function=None, compare_function=None, **kwargs):
         super(CollectionAttributeImpl, self).__init__(
-                                            class_, 
-                                            key, 
+                                            class_,
+                                            key,
                                             callable_, dispatch,
                                             trackparent=trackparent,
                                             extension=extension,
-                                            compare_function=compare_function, 
+                                            compare_function=compare_function,
                                             **kwargs)
 
         if copy_function is None:
         if self.key in state.committed_state:
             original = state.committed_state[self.key]
             if original is not NO_VALUE:
-                current_states = [((c is not None) and 
-                                    instance_state(c) or None, c) 
+                current_states = [((c is not None) and
+                                    instance_state(c) or None, c)
                                     for c in current]
-                original_states = [((c is not None) and 
-                                    instance_state(c) or None, c) 
+                original_states = [((c is not None) and
+                                    instance_state(c) or None, c)
                                     for c in original]
 
                 current_set = dict(current_states)
     def pop(self, state, dict_, value, initiator, passive=PASSIVE_OFF):
         try:
             # TODO: better solution here would be to add
-            # a "popper" role to collections.py to complement 
+            # a "popper" role to collections.py to complement
             # "remover".
             self.remove(state, dict_, value, initiator, passive=passive)
         except (ValueError, KeyError, IndexError):
             pass
 
-    def set(self, state, dict_, value, initiator, 
+    def set(self, state, dict_, value, initiator,
                     passive=PASSIVE_OFF, pop=False):
         """Set a value on the given object.
 
 
         return user_data
 
-    def get_collection(self, state, dict_, 
+    def get_collection(self, state, dict_,
                             user_data=None, passive=PASSIVE_OFF):
         """Retrieve the CollectionAdapter associated with the given state.
 
             old_state, old_dict = instance_state(oldchild),\
                                     instance_dict(oldchild)
             impl = old_state.manager[key].impl
-            impl.pop(old_state, 
-                        old_dict, 
-                        state.obj(), 
+            impl.pop(old_state,
+                        old_dict,
+                        state.obj(),
                         initiator, passive=PASSIVE_NO_FETCH)
 
         if child is not None:
             child_state, child_dict = instance_state(child),\
                                         instance_dict(child)
             child_state.manager[key].impl.append(
-                                            child_state, 
-                                            child_dict, 
-                                            state.obj(), 
-                                            initiator, 
+                                            child_state,
+                                            child_dict,
+                                            state.obj(),
+                                            initiator,
                                             passive=PASSIVE_NO_FETCH)
         return child
 
         child_state, child_dict = instance_state(child), \
                                     instance_dict(child)
         child_state.manager[key].impl.append(
-                                            child_state, 
-                                            child_dict, 
-                                            state.obj(), 
-                                            initiator, 
+                                            child_state,
+                                            child_dict,
+                                            state.obj(),
+                                            initiator,
                                             passive=PASSIVE_NO_FETCH)
         return child
 
             child_state, child_dict = instance_state(child),\
                                         instance_dict(child)
             child_state.manager[key].impl.pop(
-                                            child_state, 
-                                            child_dict, 
-                                            state.obj(), 
+                                            child_state,
+                                            child_dict,
+                                            state.obj(),
                                             initiator,
                                             passive=PASSIVE_NO_FETCH)
 
     if uselist:
-        event.listen(attribute, "append", 
-                    emit_backref_from_collection_append_event, 
+        event.listen(attribute, "append",
+                    emit_backref_from_collection_append_event,
                     retval=True, raw=True)
     else:
-        event.listen(attribute, "set", 
-                    emit_backref_from_scalar_set_event, 
+        event.listen(attribute, "set",
+                    emit_backref_from_scalar_set_event,
                     retval=True, raw=True)
     # TODO: need coverage in test/orm/ of remove event
-    event.listen(attribute, "remove", 
-                    emit_backref_from_collection_remove_event, 
+    event.listen(attribute, "remove",
+                    emit_backref_from_collection_remove_event,
                     retval=True, raw=True)
 
 _NO_HISTORY = util.symbol('NO_HISTORY')
 _NO_STATE_SYMBOLS = frozenset([
-                        id(PASSIVE_NO_RESULT), 
-                        id(NO_VALUE), 
+                        id(PASSIVE_NO_RESULT),
+                        id(NO_VALUE),
                         id(NEVER_SET)])
 class History(tuple):
     """A 3-tuple of added, unchanged and deleted values,
         return not bool(
                         (self.added or self.deleted)
                         or self.unchanged and self.unchanged != [None]
-                    ) 
+                    )
 
     def sum(self):
         """Return a collection of added + unchanged + deleted."""
         elif attribute.is_equal(current, original) is True:
             return cls((), [current], ())
         else:
-            # current convention on native scalars is to not 
+            # current convention on native scalars is to not
             # include information
             # about missing previous value in "deleted", but
             # we do include None, which helps in some primary
         elif current is original:
             return cls((), [current], ())
         else:
-            # current convention on related objects is to not 
+            # current convention on related objects is to not
             # include information
             # about missing previous value in "deleted", and
             # to also not include None - the dependency.py rules
-            # ignore the None in any case.  
+            # ignore the None in any case.
             if id(original) in _NO_STATE_SYMBOLS or original is None:
                 deleted = ()
             else:
             return cls((), list(current), ())
         else:
 
-            current_states = [((c is not None) and instance_state(c) or None, c) 
-                                for c in current 
+            current_states = [((c is not None) and instance_state(c) or None, c)
+                                for c in current
                                 ]
-            original_states = [((c is not None) and instance_state(c) or None, c) 
-                                for c in original 
+            original_states = [((c is not None) and instance_state(c) or None, c)
+                                for c in original
                                 ]
 
             current_set = dict(current_states)
 HISTORY_BLANK = History(None, None, None)
 
 def get_history(obj, key, passive=PASSIVE_OFF):
-    """Return a :class:`.History` record for the given object 
+    """Return a :class:`.History` record for the given object
     and attribute key.
 
     :param obj: an object whose class is instrumented by the
 
     :param key: string attribute name.
 
-    :param passive: indicates if the attribute should be
-      loaded from the database if not already present (:attr:`.PASSIVE_NO_FETCH`), and
-      if the attribute should be not initialized to a blank value otherwise
-      (:attr:`.PASSIVE_NO_INITIALIZE`). Default is :attr:`PASSIVE_OFF`.
+    :param passive: indicates loading behavior for the attribute
+       if the value is not already present.   This is a
+       bitflag attribute, which defaults to the symbol
+       :attr:`.PASSIVE_OFF` indicating all necessary SQL
+       should be emitted.
 
     """
     if passive is True:
     comparator = kw.pop('comparator', None)
     parententity = kw.pop('parententity', None)
     doc = kw.pop('doc', None)
-    desc = register_descriptor(class_, key, 
+    desc = register_descriptor(class_, key,
                             comparator, parententity, doc=doc)
     register_attribute_impl(class_, key, **kw)
     return desc
 
 def register_attribute_impl(class_, key,
-        uselist=False, callable_=None, 
-        useobject=False,  
+        uselist=False, callable_=None,
+        useobject=False,
         impl_class=None, backref=None, **kw):
 
     manager = manager_of_class(class_)
     manager.post_configure_attribute(key)
     return manager[key]
 
-def register_descriptor(class_, key, comparator=None, 
+def register_descriptor(class_, key, comparator=None,
                                 parententity=None, doc=None):
     manager = manager_of_class(class_)
 
             collection_adapter.append_without_event(elem)
 
     For an easier way to do the above, see
-     :func:`~sqlalchemy.orm.attributes.set_committed_value`.
+    :func:`~sqlalchemy.orm.attributes.set_committed_value`.
 
     obj is an instrumented object instance.  An InstanceState
-    is accepted directly for backwards compatibility but 
+    is accepted directly for backwards compatibility but
     this usage is deprecated.
 
     """
 def set_committed_value(instance, key, value):
     """Set the value of an attribute with no history events.
 
-    Cancels any previous history present.  The value should be 
+    Cancels any previous history present.  The value should be
     a scalar value for scalar-holding attributes, or
     an iterable for any collection-holding attribute.
 
 def flag_modified(instance, key):
     """Mark an attribute on an instance as 'modified'.
 
-    This sets the 'modified' flag on the instance and 
+    This sets the 'modified' flag on the instance and
     establishes an unconditional change event for the given attribute.
 
     """

lib/sqlalchemy/orm/state.py

 
     @util.memoized_property
     def attr(self):
+        """Return a namespace representing each attribute on
+        the mapped object, including its current value
+        and history.
+
+        The returned object is an instance of :class:`.InspectAttr`.
+
+        """
         return util.ImmutableProperties(
             dict(
                 (key, InspectAttr(self, key))
 
     @property
     def transient(self):
+        """Return true if the object is transient."""
         return self.key is None and \
             not self._attached
 
     @property
     def pending(self):
+        """Return true if the object is pending."""
         return self.key is None and \
             self._attached
 
     @property
     def persistent(self):
+        """Return true if the object is persistent."""
         return self.key is not None and \
             self._attached
 
     @property
     def detached(self):
+        """Return true if the object is detached."""
         return self.key is not None and \
             not self._attached
 
 
     @property
     def session(self):
+        """Return the owning :class:`.Session` for this instance,
+        or ``None`` if none available."""
+
         return sessionlib._state_session(self)
 
     @property
     def object(self):
+        """Return the mapped object represented by this
+        :class:`.InstanceState`."""
         return self.obj()
 
     @property
     def identity(self):
+        """Return the mapped identity of the mapped object.
+        This is the primary key identity as persisted by the ORM
+        which can always be passed directly to
+        :meth:`.Query.get`.
+
+        Returns ``None`` if the object has no primary key identity.
+
+        .. note::
+            An object which is transient or pending
+            does **not** have a mapped identity until it is flushed,
+            even if its attributes include primary key values.
+
+        """
         if self.key is None:
             return None
         else:
 
     @property
     def identity_key(self):
+        """Return the identity key for the mapped object.
+
+        This is the key used to locate the object within
+        the :attr:`.Session.identity_map` mapping.   It contains
+        the identity as returned by :attr:`.identity` within it.
+
+
+        """
         # TODO: just change .key to .identity_key across
         # the board ?  probably
         return self.key
 
     @util.memoized_property
     def mapper(self):
+        """Return the :class:`.Mapper` used for this mapepd object."""
         return self.manager.mapper
 
     @property
     def has_identity(self):
+        """Return ``True`` if this object has an identity key.
+
+        This should always have the same value as the
+        expression ``state.persistent or state.detached``.
+
+        """
         return bool(self.key)
 
     def _detach(self):
             state._strong_obj = None
 
 class InspectAttr(object):
-    """Provide inspection interface to an object's state."""
+    """Provide an inspection interface corresponding
+    to a particular attribute on a particular mapped object.
+
+    The :class:`.InspectAttr` object is created by
+    accessing the :attr:`.InstanceState.attr`
+    collection.
+
+    """
 
     def __init__(self, state, key):
         self.state = state
 
     @property
     def loaded_value(self):
+        """The current value of this attribute as loaded from the database.
+
+        If the value has not been loaded, or is otherwise not present
+        in the object's dictionary, returns NO_VALUE.
+
+        """
         return self.state.dict.get(self.key, NO_VALUE)
 
     @property
     def value(self):
+        """Return the value of this attribute.
+
+        This operation is equivalent to accessing the object's
+        attribute directly or via ``getattr()``, and will fire
+        off any pending loader callables if needed.
+
+        """
         return self.state.manager[self.key].__get__(
                         self.state.obj(), self.state.class_)
 
     @property
     def history(self):
+        """Return the current pre-flush change history for
+        this attribute, via the :class:`.History` interface.
+
+        """
         return self.state.get_history(self.key,
                     PASSIVE_NO_INITIALIZE)
 

lib/sqlalchemy/orm/util.py

     ])
 
 class AliasedInsp(_InspectionAttr, AliasedInsp):
+    """Provide an inspection interface for an
+    :class:`.AliasedClass` object.
+
+    The :class:`.AliasedInsp` object is returned
+    given an :class:`.AliasedClass` using the
+    :func:`.inspect` function::
+
+        from sqlalchemy import inspect
+        from sqlalchemy.orm import aliased
+
+        my_alias = aliased(MyMappedClass)
+        insp = inspect(my_alias)
+
+    Attributes on :class:`.AliasedInsp`
+    include:
+
+    * ``entity`` - the :class:`.AliasedClass` represented.
+    * ``mapper`` - the :class:`.Mapper` mapping the underlying class.
+    * ``selectable`` - the :class:`.Alias` construct which ultimately
+      represents an aliased :class:`.Table` or :class:`.Select`
+      construct.
+    * ``name`` - the name of the alias.  Also is used as the attribute
+      name when returned in a result tuple from :class:`.Query`.
+    * ``with_polymorphic_mappers`` - collection of :class:`.Mapper` objects
+      indicating all those mappers expressed in the select construct
+      for the :class:`.AliasedClass`.
+    * ``polymorphic_on`` - an alternate column or SQL expression which
+      will be used as the "discriminator" for a polymorphic load.
+
+    """
+
     is_aliased_class = True
+    "always returns True"
+
 
 inspection._inspects(AliasedClass)(lambda target: target._aliased_insp)
 
     """Given an object, return the primary Mapper associated with the object
     instance.
 
-    Raises UnmappedInstanceError if no mapping is configured.
+    Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
+    if no mapping is configured.
 
     This function is available via the inspection system as::
 
         inspect(instance).mapper
 
+    Using the inspection system will raise plain
+    :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
+    not part of a mapping.
+
     """
     return object_state(instance).mapper
 
 def object_state(instance):
-    """Given an object, return the primary Mapper associated with the object
-    instance.
+    """Given an object, return the :class:`.InstanceState`
+    associated with the object.
 
-    Raises UnmappedInstanceError if no mapping is configured.
+    Raises :class:`sqlalchemy.orm.exc.UnmappedInstanceError`
+    if no mapping is configured.
 
-    Equivalent functionality is available via the inspection system as::
+    Equivalent functionality is available via the :func:`.inspect`
+    function as::
 
         inspect(instance)
 
-    Using the inspection system will raise plain
-    :class:`.InvalidRequestError` if the instance is not part of
-    a mapping.
+    Using the inspection system will raise
+    :class:`sqlalchemy.exc.NoInspectionAvailable` if the instance is
+    not part of a mapping.
 
     """
     state = _inspect_mapped_object(instance)
     on the given class, or :class:`.ArgumentError` if a non-class
     object is passed.
 
-    Equivalent functionality is available via the inspection system as::
+    Equivalent functionality is available via the :func:`.inspect`
+    function as::
 
         inspect(some_mapped_class)
 

lib/sqlalchemy/util/langhelpers.py

 import sys
 import types
 import warnings
-from compat import update_wrapper, set_types, threading, callable, inspect_getfullargspec, py3k_warning
+from compat import update_wrapper, set_types, threading, \
+    callable, inspect_getfullargspec, py3k_warning
 from sqlalchemy import exc
 
 def _unique_symbols(used, *bases):
 
         from sqlalchemy import exc
         raise exc.ArgumentError(
-                "Can't load plugin: %s:%s" % 
+                "Can't load plugin: %s:%s" %
                 (self.group, name))
 
     def register(self, name, modulepath, objname):
         self_arg = None
 
     # Py3K
-    #apply_pos = inspect.formatargspec(spec[0], spec[1], spec[2], None, spec[4])
+    #apply_pos = inspect.formatargspec(spec[0], spec[1],
+    #    spec[2], None, spec[4])
     #num_defaults = 0
     #if spec[3]:
     #    num_defaults += len(spec[3])
     # end Py2K
 
     if num_defaults:
-        defaulted_vals = name_args[0-num_defaults:]
+        defaulted_vals = name_args[0 - num_defaults:]
     else:
         defaulted_vals = ()
 
-    apply_kw = inspect.formatargspec(name_args, spec[1], spec[2], defaulted_vals,
+    apply_kw = inspect.formatargspec(name_args, spec[1], spec[2],
+                                        defaulted_vals,
                                      formatvalue=lambda x: '=' + x)
     if grouped:
         return dict(args=args, self_arg=self_arg,
 def generic_repr(obj):
     """Produce a __repr__() based on direct association of the __init__()
     specification vs. same-named attributes present.
-    
+
     """
     def genargs():
         try:
         from mypackage.somemodule import somesubmod
 
     except evaluted upon attribute access to "somesubmod".
-    
+
     importlater() currently requires that resolve_all() be
     called, typically at the bottom of a package's __init__.py.
-    This is so that __import__ still called only at 
+    This is so that __import__ still called only at
     module import time, and not potentially within
     a non-main thread later on.
 
         if self in importlater._unresolved:
             raise ImportError(
                     "importlater.resolve_all() hasn't "
-                    "been called (this is %s %s)" 
+                    "been called (this is %s %s)"
                     % (self._il_path, self._il_addtl))
 
         m = self._initial_import
         importlater._unresolved.discard(self)
         if self._il_addtl:
             self._initial_import = __import__(
-                                self._il_path, globals(), locals(), 
+                                self._il_path, globals(), locals(),
                                 [self._il_addtl])
         else:
             self._initial_import = __import__(self._il_path)
 
     def __getattr__(self, key):
         if key == 'module':
-            raise ImportError("Could not resolve module %s" 
+            raise ImportError("Could not resolve module %s"
                                 % self._full_path)
         try:
             attr = getattr(self.module, key)
     If msg is a string, :class:`.exc.SAWarning` is used as
     the category.
 
-    .. note:: 
-     
+    .. note::
+
        This function is swapped out when the test suite
        runs, with a compatible version that uses
        warnings.warn_explicit, so that the warnings registry can

test/sql/test_inspect.py

+"""test the inspection registry system."""
+
+from sqlalchemy import inspect
+from sqlalchemy import Table, Column, Integer, MetaData
+from test.lib import fixtures
+from test.lib.testing import is_
+
+class TestCoreInspection(fixtures.TestBase):
+
+    def test_table(self):
+        t = Table('t', MetaData(),
+            Column('x', Integer)
+            )
+
+        is_(inspect(t), t)
+        assert t.is_selectable
+        is_(t.selectable, t)
+
+    def test_select(self):
+        t = Table('t', MetaData(),
+            Column('x', Integer)
+            )
+        s = t.select()
+
+        is_(inspect(s), s)
+        assert s.is_selectable
+        is_(s.selectable, s)
+
+    def test_column_expr(self):
+        c = Column('x', Integer)
+        is_(inspect(c), c)
+        assert not c.is_selectable
+        assert not hasattr(c, 'selectable')
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.