Mike Bayer avatar Mike Bayer committed 22ca4db

- add class_ to AliasedInsp
- redefine inspect(Class.attrname).parent to be always an inspectable
target; either Mapper or AliasedInsp
- add most major features to 08 migration, document, link

Comments (0)

Files changed (17)

doc/build/changelog/migration_08.rst

 ``2to3`` tool and maintaining a source base that works with
 Python 2 and 3 at the same time.
 
-New Features
-============
+New ORM Features
+================
 
 .. _feature_relationship_08:
 
 
 :ticket:`1401` :ticket:`610`
 
-New Class Inspection System
----------------------------
+.. _feature_orminspection_08:
+
+New Class/Object Inspection System
+----------------------------------
 
 Lots of SQLAlchemy users are writing systems that require
 the ability to inspect the attributes of a mapped class,
 
 ::
 
-    class User(Base):
-        __tablename__ = 'user'
+    >>> class User(Base):
+    ...     __tablename__ = 'user'
+    ...     id = Column(Integer, primary_key=True)
+    ...     name = Column(String)
+    ...     name_syn = synonym(name)
+    ...     addresses = relationship("Address")
+    ...
 
-        id = Column(Integer, primary_key=True)
-        name = Column(String)
-        name_syn = synonym(name)
-        addresses = relationship(Address)
-
-    # universal entry point is inspect()
+    >>> # universal entry point is inspect()
     >>> b = inspect(User)
 
-    # column collection
-    >>> b.columns
-    [<id column>, <name column>]
+    >>> # b in this case is the Mapper
+    >>> b
+    <Mapper at 0x101521950; User>
 
-    # its a ColumnCollection
+    >>> # Column namespace
     >>> b.columns.id
-    <id column>
+    Column('id', Integer(), table=<user>, primary_key=True, nullable=False)
 
-    # i.e. from mapper
+    >>> # mapper's perspective of the primary key
     >>> b.primary_key
-    (<id column>, )
+    (Column('id', Integer(), table=<user>, primary_key=True, nullable=False),)
 
-    # ColumnProperty
-    >>> b.attr.id.columns
-    [<id column>]
+    >>> # MapperProperties available from .attrs
+    >>> b.attrs.keys()
+    ['name_syn', 'addresses', 'id', 'name']
 
-    # get only column attributes
-    >>> b.column_attrs
-    [<id prop>, <name prop>]
+    >>> # .column_attrs, .relationships, etc. filter this collection
+    >>> b.column_attrs.keys()
+    ['id', 'name']
 
-    # its a namespace
+    >>> list(b.relationships)
+    [<sqlalchemy.orm.properties.RelationshipProperty object at 0x1015212d0>]
+
+    >>> # they are also namespaces
     >>> b.column_attrs.id
-    <id prop>
+    <sqlalchemy.orm.properties.ColumnProperty object at 0x101525090>
 
-    # get only relationships
-    >>> b.relationships
-    [<addresses prop>]
+    >>> b.relationships.addresses
+    <sqlalchemy.orm.properties.RelationshipProperty object at 0x1015212d0>
 
-    # its a namespace
-    >>> b.relationships.addresses
-    <addresses prop>
-
-    # point inspect() at a class level attribute,
-    # basically returns ".property"
+    >>> # point inspect() at a mapped, class level attribute,
+    >>> # returns the attribute itself
     >>> b = inspect(User.addresses)
     >>> b
-    <addresses prop>
+    <sqlalchemy.orm.attributes.InstrumentedAttribute object at 0x101521fd0>
 
-    # mapper
+    >>> # From here we can get the mapper:
     >>> b.mapper
-    <Address mapper>
+    <Mapper at 0x101525810; Address>
 
-    # None columns collection, just like columnprop has empty mapper
-    >>> b.columns
-    None
+    >>> # the parent inspector, in this case a mapper
+    >>> b.parent
+    <Mapper at 0x101521950; User>
 
-    # the parent
-    >>> b.parent
-    <User mapper>
+    >>> # an expression
+    >>> print b.expression
+    "user".id = address.user_id
 
-    # __clause_element__()
-    >>> b.expression
-    User.id==Address.user_id
-
-    >>> inspect(User.id).expression
-    <id column with ORM annotations>
-
-    # inspect works on instances !
+    >>> # inspect works on instances
     >>> u1 = User(id=3, name='x')
     >>> b = inspect(u1)
 
-    # what's b here ?  probably InstanceState
+    >>> # it returns the InstanceState
     >>> b
-    <InstanceState>
+    <sqlalchemy.orm.state.InstanceState object at 0x10152bed0>
 
-    >>> b.attr.keys()
-    ['id', 'name', 'name_syn', 'addresses']
+    >>> # similar attrs accessor refers to the
+    >>> b.attrs.keys()
+    ['id', 'name_syn', 'addresses', 'name']
 
-    # attribute interface
-    >>> b.attr.id
-    <magic attribute inspect thing>
+    >>> # attribute interface - from attrs, you get a state object
+    >>> b.attrs.id
+    <sqlalchemy.orm.state.AttributeState object at 0x10152bf90>
 
-    # value
-    >>> b.attr.id.value
+    >>> # this object can give you, current value...
+    >>> b.attrs.id.value
     3
 
-    # history
-    >>> b.attr.id.history
-    <history object>
+    >>> # ... current history
+    >>> b.attrs.id.history
+    History(added=[3], unchanged=(), deleted=())
 
-    >>> b.attr.id.history.unchanged
-    3
-
-    >>> b.attr.id.history.deleted
-    None
-
-    # lets assume the object is persistent
+    >>> # InstanceState can also provide session state information
+    >>> # lets assume the object is persistent
     >>> s = Session()
     >>> s.add(u1)
     >>> s.commit()
 
-    # big one - the primary key identity !  always
-    # works in query.get()
+    >>> # now we can get primary key identity, always
+    >>> # works in query.get()
     >>> b.identity
-    [3]
+    (3,)
 
-    # the mapper level key
+    >>> # the mapper level key
     >>> b.identity_key
-    (User, [3])
+    (<class '__main__.User'>, (3,))
 
-    >>> b.persistent
-    True
+    >>> # state within the session
+    >>> b.persistent, b.transient, b.deleted, b.detached
+    (True, False, False, False)
 
-    >>> b.transient
-    False
-
-    >>> b.deleted
-    False
-
-    >>> b.detached
-    False
-
+    >>> # owning session
     >>> b.session
-    <session>
+    <sqlalchemy.orm.session.Session object at 0x101701150>
 
 .. seealso::
 
 
 :ticket:`2208`
 
-Fully extensible, type-level operator support in Core
------------------------------------------------------
-
-The Core has to date never had any system of adding support
-for new SQL operators to Column and other expression
-constructs, other than the :meth:`.ColumnOperators.op` method
-which is "just enough" to make things work. There has also
-never been any system in place for Core which allows the
-behavior of existing operators to be overridden.   Up until
-now, the only way operators could be flexibly redefined was
-in the ORM layer, using :func:`.column_property` given a
-``comparator_factory`` argument.   Third party libraries
-like GeoAlchemy therefore were forced to be ORM-centric and
-rely upon an array of hacks to apply new opertions as well
-as to get them to propagate correctly.
-
-The new operator system in Core adds the one hook that's
-been missing all along, which is to associate new and
-overridden operators with *types*.   Since after all, it's
-not really a column, CAST operator, or SQL function that
-really drives what kinds of operations are present, it's the
-*type* of the expression.   The implementation details are
-minimal - only a few extra methods are added to the core
-:class:`.ColumnElement` type so that it consults it's
-:class:`.TypeEngine` object for an optional set of operators.
-New or revised operations can be associated with any type,
-either via subclassing of an existing type, by using
-:class:`.TypeDecorator`, or "globally across-the-board" by
-attaching a new :class:`.TypeEngine.Comparator` object to an existing type
-class.
-
-For example, to add logarithm support to :class:`.Numeric` types:
-
-::
-
-
-    from sqlalchemy.types import Numeric
-    from sqlalchemy.sql import func
-
-    class CustomNumeric(Numeric):
-        class comparator_factory(Numeric.Comparator):
-            def log(self, other):
-                return func.log(self.expr, other)
-
-The new type is usable like any other type:
-
-::
-
-
-    data = Table('data', metadata,
-              Column('id', Integer, primary_key=True),
-              Column('x', CustomNumeric(10, 5)),
-              Column('y', CustomNumeric(10, 5))
-         )
-
-    stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
-    print conn.execute(stmt).fetchall()
-
-
-New features which should come from this immediately are
-support for Postgresql's HSTORE type, which is ready to go
-in a separate library which may be merged, as well as all
-the special operations associated with Postgresql's ARRAY
-type.    It also paves the way for existing types to acquire
-lots more operators that are specific to those types, such
-as more string, integer and date operators.
-
-    .. seealso::
-
-        `Postgresql HSTORE <https://bitbucket.org/audriusk/hstore>`_ - support for HSTORE in SQLAlchemy
-
-:ticket:`2547`
-
 New with_polymorphic() feature, can be used anywhere
 ----------------------------------------------------
 
 
 ::
 
-
     # use eager loading in conjunction with with_polymorphic targets
     Job_P = with_polymorphic(Job, SubJob, aliased=True)
     q = s.query(DataContainer).\
     q = s.query(Job).join(DataContainer.jobs).\
                     filter(
                         DataContainer.jobs.of_type(Job_A).\
-                            any(and_(Job_A.id < Job.id, Job_A.type=='fred'))
+                            any(and_(Job_A.id < Job.id, Job_A.type=='fred')
+                        )
+                    )
 
+.. seealso::
+
+    :ref:`of_type`
 
 :ticket:`2438` :ticket:`1106`
 
     ReflectedOne.prepare(engine_one)
     ReflectedTwo.prepare(engine_two)
 
+.. seealso::
+
+    :class:`.DeferredReflection`
+
 :ticket:`2485`
 
+ORM Classes Now Accepted by Core Constructs
+-------------------------------------------
+
+While the SQL expressions used with :class:`.Query.filter`,
+such as ``User.id == 5``, have always been compatible for
+use with core constructs such as :func:`.select`, the mapped
+class itself would not be recognized when passed to :func:`.select`,
+:meth:`.Select.select_from`, or :meth:`.Select.correlate`.
+A new SQL registration system allows a mapped class to be
+accepted as a FROM clause within the core::
+
+    from sqlalchemy import select
+
+    stmt = select([User]).where(User.id == 5)
+
+Above, the mapped ``User`` class will expand into
+:class:`.Table` to which :class:`.User` is mapped.
+
+:ticket:`2245`
+
+Query.update() supports UPDATE..FROM
+-------------------------------------
+
+The new UPDATE..FROM mechanics work in query.update().
+Below, we emit an UPDATE against ``SomeEntity``, adding
+a FROM clause (or equivalent, depending on backend)
+against ``SomeOtherEntity``::
+
+    query(SomeEntity).\
+        filter(SomeEntity.id==SomeOtherEntity.id).\
+        filter(SomeOtherEntity.foo=='bar').\
+        update({"data":"x"})
+
+In particular, updates to joined-inheritance
+entities are supported, provided the target of the UPDATE is local to the
+table being filtered on, or if the parent and child tables
+are mixed, they are joined explicitly in the query.  Below,
+given ``Engineer`` as a joined subclass of ``Person``:
+
+::
+
+    query(Engineer).\
+            filter(Person.id==Engineer.id).\
+            filter(Person.name=='dilbert').\
+            update({"engineer_data":"java"})
+
+would produce:
+
+::
+
+    UPDATE engineer SET engineer_data='java' FROM person
+    WHERE person.id=engineer.id AND person.name='dilbert'
+
+:ticket:`2365`
+
+rollback() will only roll back "dirty" objects from a begin_nested()
+--------------------------------------------------------------------
+
+A behavioral change that should improve efficiency for those
+users using SAVEPOINT via ``Session.begin_nested()`` - upon
+``rollback()``, only those objects that were made dirty
+since the last flush will be expired, the rest of the
+``Session`` remains intact.  This because a ROLLBACK to a
+SAVEPOINT does not terminate the containing transaction's
+isolation, so no expiry is needed except for those changes
+that were not flushed in the current transaction.
+
+:ticket:`2452`
+
+Caching Example now uses dogpile.cache
+---------------------------------------
+
+The caching example now uses `dogpile.cache <http://dogpilecache.readthedocs.org/>`_.
+Dogpile.cache is a rewrite of the caching portion
+of Beaker, featuring vastly simpler and faster operation,
+as well as support for distributed locking.
+
+.. seealso::
+
+    :mod:`dogpile_caching`
+
+:ticket:`2589`
+
+New Core Features
+==================
+
+Fully extensible, type-level operator support in Core
+-----------------------------------------------------
+
+The Core has to date never had any system of adding support
+for new SQL operators to Column and other expression
+constructs, other than the :meth:`.ColumnOperators.op` method
+which is "just enough" to make things work. There has also
+never been any system in place for Core which allows the
+behavior of existing operators to be overridden.   Up until
+now, the only way operators could be flexibly redefined was
+in the ORM layer, using :func:`.column_property` given a
+``comparator_factory`` argument.   Third party libraries
+like GeoAlchemy therefore were forced to be ORM-centric and
+rely upon an array of hacks to apply new opertions as well
+as to get them to propagate correctly.
+
+The new operator system in Core adds the one hook that's
+been missing all along, which is to associate new and
+overridden operators with *types*.   Since after all, it's
+not really a column, CAST operator, or SQL function that
+really drives what kinds of operations are present, it's the
+*type* of the expression.   The implementation details are
+minimal - only a few extra methods are added to the core
+:class:`.ColumnElement` type so that it consults it's
+:class:`.TypeEngine` object for an optional set of operators.
+New or revised operations can be associated with any type,
+either via subclassing of an existing type, by using
+:class:`.TypeDecorator`, or "globally across-the-board" by
+attaching a new :class:`.TypeEngine.Comparator` object to an existing type
+class.
+
+For example, to add logarithm support to :class:`.Numeric` types:
+
+::
+
+
+    from sqlalchemy.types import Numeric
+    from sqlalchemy.sql import func
+
+    class CustomNumeric(Numeric):
+        class comparator_factory(Numeric.Comparator):
+            def log(self, other):
+                return func.log(self.expr, other)
+
+The new type is usable like any other type:
+
+::
+
+
+    data = Table('data', metadata,
+              Column('id', Integer, primary_key=True),
+              Column('x', CustomNumeric(10, 5)),
+              Column('y', CustomNumeric(10, 5))
+         )
+
+    stmt = select([data.c.x.log(data.c.y)]).where(data.c.x.log(2) < value)
+    print conn.execute(stmt).fetchall()
+
+
+New features which should come from this immediately are
+support for Postgresql's HSTORE type, which is ready to go
+in a separate library which may be merged, as well as all
+the special operations associated with Postgresql's ARRAY
+type.    It also paves the way for existing types to acquire
+lots more operators that are specific to those types, such
+as more string, integer and date operators.
+
+.. seealso::
+
+    :ref:`types_operators`
+
+    `Postgresql HSTORE <https://bitbucket.org/audriusk/hstore>`_ - support for HSTORE in SQLAlchemy
+
+:ticket:`2547`
+
+Type Expressions
+-----------------
+
+SQL expressions can now be associated with types.  Historically,
+:class:`.TypeEngine` has always allowed Python-side functions which
+receive both bound parameters as well as result row values, passing
+them through a Python side conversion function on the way to/back from
+the database.   The new feature allows similar
+functionality, except on the database side::
+
+    from sqlalchemy.types import String
+    from sqlalchemy import func, Table, Column, MetaData
+
+    class LowerString(String):
+        def bind_expression(self, bindvalue):
+            return func.lower(bindvalue)
+
+        def column_expression(self, col):
+            return func.lower(col)
+
+    metadata = MetaData()
+    test_table = Table(
+            'test_table',
+            metadata,
+            Column('data', LowerString)
+    )
+
+Above, the ``LowerString`` type defines a SQL expression that will be emitted
+whenever the ``test_table.c.data`` column is rendered in the columns
+clause of a SELECT statement::
+
+    >>> print select([test_table]).where(test_table.c.data == 'HI')
+    SELECT lower(test_table.data) AS data
+    FROM test_table
+    WHERE test_table.data = lower(:data_1)
+
+This feature is also used heavily by the new release of GeoAlchemy,
+to embed PostGIS expressions inline in SQL based on type rules.
+
+.. seealso::
+
+    :ref:`types_sql_value_processing`
+
+:ticket:`1534`
+
+Core Inspection System
+-----------------------
+
+The :func:`.inspect` function introduced in :ref:`feature_orminspection_08`
+also applies to the core.  Applied to an :class:`.Engine` it produces
+an :class:`.Inspector` object::
+
+    from sqlalchemy import inspect
+    from sqlalchemy import create_engine
+
+    engine = create_engine("postgresql://scott:tiger@localhost/test")
+    insp = inspect(engine)
+    print insp.get_table_names()
+
+It can also be applied to any :class:`.ClauseElement`, which returns
+the :class:`.ClauseElement` itself, such as :class:`.Table`, :class:`.Column`,
+:class:`.Select`, etc.   This allows it to work fluently between Core
+and ORM constructs.
+
 New, configurable DATE, TIME types for SQLite
 ---------------------------------------------
 
                     )
                 )
 
+Huge thanks to Nate Dub for the sprinting on this at Pycon 2012.
 
-Huge thanks to Nate Dub for the sprinting on this at Pycon
-'12.
+.. seealso::
+
+    :class:`.sqlite.DATETIME`
+
+    :class:`.sqlite.DATE`
+
+    :class:`.sqlite.TIME`
 
 :ticket:`2363`
 
-Query.update() will support UPDATE..FROM
-----------------------------------------
+New Method :meth:`.Select.correlate_except`
+-------------------------------------------
 
-Not 100% sure if this will make it in, the new UPDATE..FROM
-mechanics should work in query.update():
+:func:`.select` now has a method :meth:`.Select.correlate_except`
+which specifies "correlate on all FROM clauses except those
+specified".  It can be used for mapping scenarios where
+a related subquery should correlate normally, except
+against a particular target selectable::
 
-::
+    class SnortEvent(Base):
+        __tablename__ = "event"
 
-    query(SomeEntity).\
-        filter(SomeEntity.id==SomeOtherEntity.id).\
-        filter(SomeOtherEntity.foo=='bar').\
-        update({"data":"x"})
+        id = Column(Integer, primary_key=True)
+        signature = Column(Integer, ForeignKey("signature.id"))
 
-Should also work when used against a joined-inheritance
-entity, provided the target of the UPDATE is local to the
-table being filtered on, or if the parent and child tables
-are mixed, they are joined explicitly in the query.  Below,
-given ``Engineer`` as a joined subclass of ``Person``:
+        signatures = relationship("Signature", lazy=False)
 
-::
+    class Signature(Base):
+        __tablename__ = "signature"
 
-    query(Engineer).\
-            filter(Person.id==Engineer.id).\
-            filter(Person.name=='dilbert').\
-            update({"engineer_data":"java"})
+        id = Column(Integer, primary_key=True)
 
-would produce:
+        sig_count = column_property(
+                        select([func.count('*')]).\
+                            where(SnortEvent.signature == id).
+                            correlate_except(SnortEvent)
+                    )
 
-::
+.. seealso::
 
-    UPDATE engineer SET engineer_data='java' FROM person
-    WHERE person.id=engineer.id AND person.name='dilbert'
-
-:ticket:`2365`
+    :meth:`.Select.correlate_except`
 
 Enhanced Postgresql ARRAY type
 ------------------------------
     # to guess how many levels deep to go
     Column("my_array", postgresql.ARRAY(Integer, dimensions=2))
 
+.. seealso::
+
+    :class:`.postgresql.ARRAY`
+
 :ticket:`2441`
 
-rollback() will only roll back "dirty" objects from a begin_nested()
---------------------------------------------------------------------
+"COLLATE" supported across all dialects; in particular MySQL, Postgresql, SQLite
+--------------------------------------------------------------------------------
 
-A behavioral change that should improve efficiency for those
-users using SAVEPOINT via ``Session.begin_nested()`` - upon
-``rollback()``, only those objects that were made dirty
-since the last flush will be expired, the rest of the
-``Session`` remains intact.  This because a ROLLBACK to a
-SAVEPOINT does not terminate the containing transaction's
-isolation, so no expiry is needed except for those changes
-that were not flushed in the current transaction.
+The "collate" keyword, long accepted by the MySQL dialect, is now established
+on all :class:`.String` types and will render on any backend, including
+when features such as :meth:`.MetaData.create_all` and :func:`.cast` is used::
 
-:ticket:`2452`
+    >>> stmt = select([cast(sometable.c.somechar, String(20, collation='utf8'))])
+    >>> print stmt
+    SELECT CAST(sometable.somechar AS VARCHAR(20) COLLATE "utf8") AS anon_1
+    FROM sometable
+
+.. seealso::
+
+    :class:`.String`
+
+:ticket:`2276`
+
+"Prefixes" now supported for :func:`.insert`, :func:`.update`, :func:`.delete`
+-------------------------------------------------------------------------------
+
+Geared towards MySQL, a "prefix" can be rendered within any of these
+statements::
+
+    stmt = table.insert().prefix_with("LOW_PRIORITY", dialect="mysql")
+
+
+    stmt = table.update().prefix_with("LOW_PRIORITY", dialect="mysql")
+
+.. seealso::
+
+    :meth:`.Insert.prefix_with`
+
+    :meth:`.Update.prefix_with`
+
+    :meth:`.Delete.prefix_with`
+
+    :meth:`.Select.prefix_with`
+
+:ticket:`2431`
+
 
 Behavioral Changes
 ==================

doc/build/conf.py

 # Add any Sphinx extension module names here, as strings. They can be extensions
 # coming with Sphinx (named 'sphinx.ext.*') or your custom ones.
 
-extensions = ['sphinx.ext.autodoc',
-                'sphinx.ext.doctest',
+extensions = [
+            'sphinx.ext.autodoc',
+            #    'sphinx.ext.doctest',
                 'builder.autodoc_mods',
                 'builder.changelog',
                 'builder.dialect_info',

doc/build/core/inspection.rst

 .. _core_inspection_toplevel:
+.. _inspection_toplevel:
 
 Runtime Inpection API
 =====================
 * ``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`.
+  as ``inspect(MyClass.some_attribute)``, returns a :class:`.QueryableAttribute`
+  object, which is the :term:`descriptor` associated with a mapped class.
+  This descriptor refers to a :class:`.MapperProperty`, which is usually
+  an instance of :class:`.ColumnProperty`
+  or :class:`.RelationshipProperty`, via its :attr:`.QueryableAttribute.property`
+  attribute.
 * :class:`.AliasedClass` - returns an :class:`.AliasedInsp` object.
 

doc/build/core/tutorial.rst

     ()
     {stop}[(u'jack', 2), (u'wendy', 2), (u'fred', 0), (u'mary', 0)]
 
+.. _correlated_subqueries:
+
 Correlated Subqueries
 ---------------------
 

doc/build/core/types.rst

    :members:
    :show-inheritance:
 
-   .. autoclass:: TypeEngine.Comparator
-   .. automethod:: _adapt_expression
 
 .. autoclass:: Concatenable
    :members:

doc/build/glossary.rst

 
 .. glossary::
 
+    descriptor
+        In Python, a descriptor is an object attribute with “binding behavior”, one whose attribute access has been overridden by methods in the `descriptor protocol <http://docs.python.org/howto/descriptor.html>`_.
+        Those methods are __get__(), __set__(), and __delete__(). If any of those methods are defined
+        for an object, it is said to be a descriptor.
+
+        In SQLAlchemy, descriptors are used heavily in order to provide attribute behavior
+        on mapped classes.   When a class is mapped as such::
+
+            class MyClass(Base):
+                __tablename__ = 'foo'
+
+                id = Column(Integer, primary_key=True)
+                data = Column(String)
+
+        The ``MyClass`` class will be :term:`mapped` when its definition
+        is complete, at which point the ``id`` and ``data`` attributes,
+        starting out as :class:`.Column` objects, will be replaced
+        by the :term:`instrumentation` system with instances
+        of :class:`.InstrumentedAttribute`, which are descriptors that
+        provide the above mentioned ``__get__()``, ``__set__()`` and
+        ``__delete__()`` methods.   The :class:`.InstrumentedAttribute`
+        will generate a SQL expression when used at the class level::
+
+            >>> print MyClass.data == 5
+            data = :data_1
+
+        and at the instance level, keeps track of changes to values,
+        and also :term:`lazy loads` unloaded attributes
+        from the database::
+
+            >>> m1 = MyClass()
+            >>> m1.id = 5
+            >>> m1.data = "some data"
+
+            >>> from sqlalchemy import inspect
+            >>> inspect(m1).attrs.data.history.added
+            "some data"
+
+    instrumentation
+    instrumented
+        Instrumentation refers to the process of augmenting the functionality
+        and attribute set of a particular class.   Ideally, the
+        behavior of the class should remain close to a regular
+        class, except that additional behviors and features are
+        made available.  The SQLAlchemy :term:`mapping` process,
+        among other things, adds database-enabled :term:`descriptors`
+        to a mapped
+        class which each represent a particular database column
+        or relationship to a related class.
+
+    mapping
+    mapped
+        We say a class is "mapped" when it has been passed through the
+        :func:`.orm.mapper` function.   This process associates the
+        class with a database table or other :term:`selectable`
+        construct, so that instances of it can be persisted
+        using a :class:`.Session` as well as loaded using a
+        :class:`.Query`.
+
     release
     releases
     released

doc/build/index.rst

 :ref:`Overview <overview>` |
 :ref:`Installation Guide <installation>` |
 :doc:`Migration from 0.7 <changelog/migration_08>` |
+:doc:`Glossary <glossary>` |
 :doc:`Changelog catalog <changelog/index>`
 
 SQLAlchemy ORM

doc/build/orm/extensions/declarative.rst

 ===========
 
 .. automodule:: sqlalchemy.ext.declarative
- 
+
 API Reference
 -------------
 
 
 .. autoclass:: declared_attr
 
-.. autofunction:: _declarative_constructor
+.. autofunction:: sqlalchemy.ext.declarative.api._declarative_constructor
 
 .. autofunction:: has_inherited_table
 

doc/build/orm/inheritance.rst

     session.query(engineer.c.id).\
             filter(engineer.c.engineer_info==manager.c.manager_data)
 
+.. _of_type:
+
 Creating Joins to Specific Subtypes
 +++++++++++++++++++++++++++++++++++
 

doc/build/orm/internals.rst

     :members:
     :show-inheritance:
 
+.. autoclass:: sqlalchemy.orm.attributes.InstrumentedAttribute
+    :members:
+    :show-inheritance:
+
 .. autoclass:: sqlalchemy.orm.interfaces.MapperProperty
     :members:
     :show-inheritance:
 .. autoclass:: sqlalchemy.orm.query.QueryContext
     :members:
     :show-inheritance:
+
+.. autoclass:: sqlalchemy.orm.attributes.QueryableAttribute
+    :members:
+    :show-inheritance:

doc/build/orm/session.rst

     as they each emit an informative exception
     if the given object is not mapped.
 
-.. autofunction:: is_instrumented
+.. autofunction:: sqlalchemy.orm.instrumentation.is_instrumented
 
 .. autofunction:: set_attribute
 

lib/sqlalchemy/orm/attributes.py

         # TODO: conditionally attach this method based on clause_element ?
         return self
 
-    @property
+    @util.memoized_property
     def parent(self):
-        return self._parententity
+        """Return an inspection instance representing the parent.
+
+        This will be either an instance of :class:`.Mapper`
+        or :class:`.AliasedInsp`, depending upon the nature
+        of the parent entity which this attribute is associated
+        with.
+
+        """
+        return inspection.inspect(self._parententity)
 
     @property
     def expression(self):
 
     @util.memoized_property
     def property(self):
+        """Return the :class:`.MapperProperty` associated with this
+        :class:`.QueryableAttribute`.
+
+
+        Return values here will commonly be instances of
+        :class:`.ColumnProperty` or :class:`.RelationshipProperty`.
+
+
+        """
         return self.comparator.property
 
 inspection._self_inspects(QueryableAttribute)

lib/sqlalchemy/orm/properties.py

             return self.property.mapper
 
         @util.memoized_property
-        def parent(self):
-            """The parent :class:`.Mapper` or :class:`.AliasedClass`
-            referred to by this
-            :class:`.RelationshipProperty.Comparator.
-
-            This is the "parent" or "local" side of the
-            :func:`.relationship`.
-
-            """
+        def _parententity(self):
             return self.property.parent
 
-        @util.memoized_property
-        def _parententity(self):
-            return self.parent
-
         def _source_selectable(self):
             elem = self.property.parent._with_polymorphic_selectable
             if self.adapter:

lib/sqlalchemy/orm/query.py

                         right_entity = onclause.property.mapper
 
                 left_entity = onclause._parententity
-                assert left_entity is onclause.parent
 
                 prop = onclause.property
                 if not isinstance(onclause,  attributes.QueryableAttribute):

lib/sqlalchemy/orm/util.py

     * ``polymorphic_on`` - an alternate column or SQL expression which
       will be used as the "discriminator" for a polymorphic load.
 
+    .. seealso::
+
+        :ref:`inspection_toplevel`
+
     """
 
     is_aliased_class = True
     "always returns True"
 
+    @property
+    def class_(self):
+        """Return the mapped class ultimately represented by this
+        :class:`.AliasedInsp`."""
+        return self.mapper.class_
 
 inspection._inspects(AliasedClass)(lambda target: target._aliased_insp)
 

lib/sqlalchemy/sql/expression.py

         If the fromclause is None, correlation is disabled for the returned
         select().
 
+        .. seealso::
+
+            :meth:`.Select.correlate_except`
+
+            :ref:`correlated_subqueries`
+
         """
         self._should_correlate = False
         if fromclauses and fromclauses[0] is None:
 
     @_generative
     def correlate_except(self, *fromclauses):
+        """"Return a new select() construct which will auto-correlate
+        on FROM clauses of enclosing selectables, except for those FROM
+        clauses specified here.
+
+        .. seealso::
+
+            :meth:`.Select.correlate`
+
+            :ref:`correlated_subqueries`
+
+        """
         self._should_correlate = False
         if fromclauses and fromclauses[0] is None:
             self._correlate_except = ()

test/orm/test_inspect.py

         prop = inspect(ua.addresses)
         is_(prop, ua.addresses)
 
-        is_(prop.property.parent, class_mapper(User))
+        is_(prop.property.parent.mapper, class_mapper(User))
         is_(prop.property.mapper, class_mapper(Address))
-        is_(prop.parent, ua)
+        is_(prop.parent.entity, ua)
+        is_(prop.parent.class_, User)
         is_(prop._parentmapper, class_mapper(User))
         is_(prop.mapper, class_mapper(Address))
 
         prop = inspect(ua.name)
         is_(prop, ua.name)
 
-        is_(prop.property.parent, class_mapper(User))
+        is_(prop.property.parent.mapper, class_mapper(User))
         assert not hasattr(prop.property, "mapper")
-        is_(prop.parent, ua)
+        is_(prop.parent.entity, ua)
+        is_(prop.parent.class_, User)
         is_(prop._parentmapper, class_mapper(User))
 
         assert not hasattr(prop, "mapper")
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.