]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- removed cascade_mappers(). long overdue.
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 2 Jun 2007 19:06:13 +0000 (19:06 +0000)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 2 Jun 2007 19:06:13 +0000 (19:06 +0000)
- removed sqlalchemy.orm from sqlalchemy.__init__ namespace.  still
needs updates in documentation, tutorial pages
- moved MapperExtension to interfaces package
- moved ExtensionCarrier to orm.util

40 files changed:
lib/sqlalchemy/__init__.py
lib/sqlalchemy/ext/assignmapper.py
lib/sqlalchemy/ext/sessioncontext.py
lib/sqlalchemy/mods/threadlocal.py
lib/sqlalchemy/orm/__init__.py
lib/sqlalchemy/orm/interfaces.py
lib/sqlalchemy/orm/mapper.py
lib/sqlalchemy/orm/properties.py
lib/sqlalchemy/orm/query.py
lib/sqlalchemy/orm/strategies.py
lib/sqlalchemy/orm/util.py
test/orm/association.py
test/orm/cascade.py
test/orm/compile.py
test/orm/cycles.py
test/orm/eagertest1.py
test/orm/eagertest2.py
test/orm/eagertest3.py
test/orm/entity.py
test/orm/generative.py
test/orm/inheritance/abc_inheritance.py
test/orm/inheritance/basic.py
test/orm/inheritance/concrete.py
test/orm/inheritance/magazine.py
test/orm/inheritance/manytomany.py
test/orm/inheritance/poly_linked_list.py
test/orm/inheritance/polymorph.py
test/orm/inheritance/polymorph2.py
test/orm/inheritance/productspec.py
test/orm/inheritance/single.py
test/orm/lazytest1.py
test/orm/manytomany.py
test/orm/mapper.py
test/orm/memusage.py
test/orm/merge.py
test/orm/onetoone.py
test/orm/relationships.py
test/orm/session.py
test/orm/sessioncontext.py
test/orm/unitofwork.py

index 22fb10ffd965a7eac8ce624fb773855666ec9fff..0d8f670b946ef04f5d547439ad38089f3c78339c 100644 (file)
@@ -7,7 +7,6 @@
 from sqlalchemy.types import *
 from sqlalchemy.sql import *
 from sqlalchemy.schema import *
-from sqlalchemy.orm import *
 
 from sqlalchemy.engine import create_engine
 from sqlalchemy.schema import default_metadata
index 7886f4d272316817bdc64e3da3bcad411406f99a..23c6cc9ae99cfa316531caf81da3b2a87c005b68 100644 (file)
@@ -1,5 +1,6 @@
-from sqlalchemy import mapper, util, Query, exceptions
+from sqlalchemy import util, exceptions
 import types
+from sqlalchemy.orm import mapper, Query
 
 def monkeypatch_query_method(ctx, class_, name):
     def do(self, *args, **kwargs):
index 5a0e0afc77911c12c2f98dfa0eff235aca41f071..385c034ddfdcccad27a275c450049314f762ff30 100644 (file)
@@ -1,6 +1,5 @@
 from sqlalchemy.util import ScopedRegistry
-from sqlalchemy.orm.mapper import MapperExtension, EXT_PASS
-from sqlalchemy.orm import create_session
+from sqlalchemy.orm import create_session, MapperExtension, EXT_PASS
 
 __all__ = ['SessionContext', 'SessionContextExt']
 
index c8043bc624744442dbb7acc5d993455af6d63eed..292479e7b60870e0277828c1bb1b13a8a554b2e9 100644 (file)
@@ -19,7 +19,7 @@ installed will reference this global context when creating new mapped
 object instances.
 """
 
-from sqlalchemy import util, engine, mapper
+from sqlalchemy import util, engine
 from sqlalchemy.ext.sessioncontext import SessionContext
 import sqlalchemy.ext.assignmapper as assignmapper
 from sqlalchemy.orm.mapper import global_extensions
index 83a31eee24f2accc0557b9d691559df35a1e0396..eeefe1d7553359a4b2fbfe445372f764023bc315 100644 (file)
@@ -11,17 +11,18 @@ packages and tying operations to class properties and constructors.
 
 from sqlalchemy import exceptions
 from sqlalchemy import util as sautil
-from sqlalchemy.orm.mapper import *
+from sqlalchemy.orm.mapper import Mapper, object_mapper, class_mapper, mapper_registry
+from sqlalchemy.orm.interfaces import SynonymProperty, MapperExtension, EXT_PASS, ExtensionOption
+from sqlalchemy.orm.properties import PropertyLoader, ColumnProperty, BackRef
 from sqlalchemy.orm import mapper as mapperlib
 from sqlalchemy.orm.query import Query
 from sqlalchemy.orm.util import polymorphic_union
-from sqlalchemy.orm import properties, strategies, interfaces
 from sqlalchemy.orm.session import Session as create_session
 from sqlalchemy.orm.session import object_session, attribute_manager
 
 __all__ = ['relation', 'column_property', 'backref', 'eagerload', 'lazyload', 'noload', 'deferred', 'defer', 'undefer', 'undefer_group', 'extension',
         'mapper', 'clear_mappers', 'compile_mappers', 'clear_mapper', 'class_mapper', 'object_mapper', 'MapperExtension', 'Query',
-        'cascade_mappers', 'polymorphic_union', 'create_session', 'synonym', 'contains_alias', 'contains_eager', 'EXT_PASS', 'object_session'
+        'polymorphic_union', 'create_session', 'synonym', 'contains_alias', 'contains_eager', 'EXT_PASS', 'object_session'
         ]
 
 def relation(*args, **kwargs):
@@ -59,10 +60,10 @@ def column_property(*args, **kwargs):
     no direct correspondence to the mapped selectable will effectively be non-persisted
     attributes.
     """
-    return properties.ColumnProperty(*args, **kwargs)
+    return ColumnProperty(*args, **kwargs)
     
 def _relation_loader(mapper, secondary=None, primaryjoin=None, secondaryjoin=None, lazy=True, **kwargs):
-    return properties.PropertyLoader(mapper, secondary, primaryjoin, secondaryjoin, lazy=lazy, **kwargs)
+    return PropertyLoader(mapper, secondary, primaryjoin, secondaryjoin, lazy=lazy, **kwargs)
 
 def backref(name, **kwargs):
     """Create a BackRef object with explicit arguments, which are the same arguments one
@@ -72,7 +73,7 @@ def backref(name, **kwargs):
     place of a string argument.
     """
 
-    return properties.BackRef(name, **kwargs)
+    return BackRef(name, **kwargs)
 
 def deferred(*columns, **kwargs):
     """Return a ``DeferredColumnProperty``, which indicates this
@@ -82,7 +83,7 @@ def deferred(*columns, **kwargs):
     Used with the `properties` dictionary sent to ``mapper()``.
     """
 
-    return properties.ColumnProperty(deferred=True, *columns, **kwargs)
+    return ColumnProperty(deferred=True, *columns, **kwargs)
 
 def mapper(class_, table=None, *args, **params):
     """Return a new ``Mapper`` object.
@@ -98,7 +99,7 @@ def synonym(name, proxy=False):
     Used with the `properties` dictionary sent to ``mapper()``.
     """
 
-    return interfaces.SynonymProperty(name, proxy=proxy)
+    return SynonymProperty(name, proxy=proxy)
 
 def compile_mappers():
     """Compile all mappers that have been defined.
@@ -249,63 +250,3 @@ def undefer_group(name):
     """
     return strategies.UndeferGroupOption(name)
     
-def cascade_mappers(*classes_or_mappers):
-    """Attempt to create a series of ``relations()`` between mappers
-    automatically, via introspecting the foreign key relationships of
-    the underlying tables.
-
-    Given a list of classes and/or mappers, identify the foreign key
-    relationships between the given mappers or corresponding class
-    mappers, and create ``relation()`` objects representing those
-    relationships, including a backreference. Attempt to find the
-    *secondary* table in a many-to-many relationship as well.
-
-    The names of the relations will be a lowercase version of the
-    related class.  In the case of one-to-many or many-to-many, the
-    name will be *pluralized*, which currently is based on the English
-    language (i.e. an 's' or 'es' added to it).
-
-    NOTE: this method usually works poorly, and its usage is generally
-    not advised.
-    """
-
-    table_to_mapper = {}
-    for item in classes_or_mappers:
-        if isinstance(item, Mapper):
-            m = item
-        else:
-            klass = item
-            m = class_mapper(klass)
-        table_to_mapper[m.mapped_table] = m
-
-    def pluralize(name):
-        # oh crap, do we need locale stuff now
-        if name[-1] == 's':
-            return name + "es"
-        else:
-            return name + "s"
-
-    for table,mapper in table_to_mapper.iteritems():
-        for fk in table.foreign_keys:
-            if fk.column.table is table:
-                continue
-            secondary = None
-            try:
-                m2 = table_to_mapper[fk.column.table]
-            except KeyError:
-                if len(fk.column.table.primary_key):
-                    continue
-                for sfk in fk.column.table.foreign_keys:
-                    if sfk.column.table is table:
-                        continue
-                    m2 = table_to_mapper.get(sfk.column.table)
-                    secondary = fk.column.table
-            if m2 is None:
-                continue
-            if secondary:
-                propname = pluralize(m2.class_.__name__.lower())
-                propname2 = pluralize(mapper.class_.__name__.lower())
-            else:
-                propname = m2.class_.__name__.lower()
-                propname2 = pluralize(mapper.class_.__name__.lower())
-            mapper.add_property(propname, relation(m2, secondary=secondary, backref=propname2))
index c5da017322949c8cd83bb4f9bd11f9f88b3a2530..caa5e4412a3588455209c5ad07fac9623dba7cba 100644 (file)
@@ -7,6 +7,198 @@
 
 from sqlalchemy import util, logging
 
+# returned by a MapperExtension method to indicate a "do nothing" response
+EXT_PASS = object()
+
+class MapperExtension(object):
+    """Base implementation for an object that provides overriding
+    behavior to various Mapper functions.  For each method in
+    MapperExtension, a result of EXT_PASS indicates the functionality
+    is not overridden.
+    """
+
+
+    def init_instance(self, mapper, class_, instance, args, kwargs):
+        return EXT_PASS
+
+    def init_failed(self, mapper, class_, instance, args, kwargs):
+        return EXT_PASS
+
+    def get_session(self):
+        """Retrieve a contextual Session instance with which to
+        register a new object.
+
+        Note: this is not called if a session is provided with the
+        `__init__` params (i.e. `_sa_session`).
+        """
+
+        return EXT_PASS
+
+    def load(self, query, *args, **kwargs):
+        """Override the `load` method of the Query object.
+
+        The return value of this method is used as the result of
+        ``query.load()`` if the value is anything other than EXT_PASS.
+        """
+
+        return EXT_PASS
+
+    def get(self, query, *args, **kwargs):
+        """Override the `get` method of the Query object.
+
+        The return value of this method is used as the result of
+        ``query.get()`` if the value is anything other than EXT_PASS.
+        """
+
+        return EXT_PASS
+
+    def get_by(self, query, *args, **kwargs):
+        """Override the `get_by` method of the Query object.
+
+        The return value of this method is used as the result of
+        ``query.get_by()`` if the value is anything other than
+        EXT_PASS.
+        """
+
+        return EXT_PASS
+
+    def select_by(self, query, *args, **kwargs):
+        """Override the `select_by` method of the Query object.
+
+        The return value of this method is used as the result of
+        ``query.select_by()`` if the value is anything other than
+        EXT_PASS.
+        """
+
+        return EXT_PASS
+
+    def select(self, query, *args, **kwargs):
+        """Override the `select` method of the Query object.
+
+        The return value of this method is used as the result of
+        ``query.select()`` if the value is anything other than
+        EXT_PASS.
+        """
+
+        return EXT_PASS
+
+
+    def translate_row(self, mapper, context, row):
+        """Perform pre-processing on the given result row and return a
+        new row instance.
+
+        This is called as the very first step in the ``_instance()``
+        method.
+        """
+
+        return EXT_PASS
+
+    def create_instance(self, mapper, selectcontext, row, class_):
+        """Receive a row when a new object instance is about to be
+        created from that row.
+
+        The method can choose to create the instance itself, or it can
+        return None to indicate normal object creation should take
+        place.
+
+        mapper
+          The mapper doing the operation
+
+        selectcontext
+          SelectionContext corresponding to the instances() call
+
+        row
+          The result row from the database
+
+        class\_
+          The class we are mapping.
+        """
+
+        return EXT_PASS
+
+    def append_result(self, mapper, selectcontext, row, instance, result, **flags):
+        """Receive an object instance before that instance is appended
+        to a result list.
+
+        If this method returns EXT_PASS, result appending will proceed
+        normally.  if this method returns any other value or None,
+        result appending will not proceed for this instance, giving
+        this extension an opportunity to do the appending itself, if
+        desired.
+
+        mapper
+          The mapper doing the operation.
+
+        selectcontext
+          SelectionContext corresponding to the instances() call.
+
+        row
+          The result row from the database.
+
+        instance
+          The object instance to be appended to the result.
+
+        result
+          List to which results are being appended.
+
+        \**flags
+          extra information about the row, same as criterion in
+          `create_row_processor()` method of [sqlalchemy.orm.interfaces#MapperProperty]
+        """
+
+        return EXT_PASS
+
+    def populate_instance(self, mapper, selectcontext, row, instance, **flags):
+        """Receive a newly-created instance before that instance has
+        its attributes populated.
+
+        The normal population of attributes is according to each
+        attribute's corresponding MapperProperty (which includes
+        column-based attributes as well as relationships to other
+        classes).  If this method returns EXT_PASS, instance
+        population will proceed normally.  If any other value or None
+        is returned, instance population will not proceed, giving this
+        extension an opportunity to populate the instance itself, if
+        desired.
+        """
+
+        return EXT_PASS
+
+    def before_insert(self, mapper, connection, instance):
+        """Receive an object instance before that instance is INSERTed
+        into its table.
+
+        This is a good place to set up primary key values and such
+        that aren't handled otherwise.
+        """
+
+        return EXT_PASS
+
+    def before_update(self, mapper, connection, instance):
+        """Receive an object instance before that instance is UPDATEed."""
+
+        return EXT_PASS
+
+    def after_update(self, mapper, connection, instance):
+        """Receive an object instance after that instance is UPDATEed."""
+
+        return EXT_PASS
+
+    def after_insert(self, mapper, connection, instance):
+        """Receive an object instance after that instance is INSERTed."""
+
+        return EXT_PASS
+
+    def before_delete(self, mapper, connection, instance):
+        """Receive an object instance before that instance is DELETEed."""
+
+        return EXT_PASS
+
+    def after_delete(self, mapper, connection, instance):
+        """Receive an object instance after that instance is DELETEed."""
+
+        return EXT_PASS
+
 class MapperProperty(object):
     """Manage the relationship of a ``Mapper`` to a single class
     attribute, as well as that attribute as it appears on individual
@@ -75,6 +267,9 @@ class MapperProperty(object):
     def set_parent(self, parent):
         self.parent = parent
 
+    def get_sub_mapper(self):
+        raise NotImplementedError()
+
     def init(self, key, parent):
         """Called after all mappers are compiled to assemble
         relationships between mappers, establish instrumented class
@@ -123,33 +318,7 @@ class MapperProperty(object):
 
         raise NotImplementedError()
 
-class SynonymProperty(MapperProperty):
-    def __init__(self, name, proxy=False):
-        self.name = name
-        self.proxy = proxy
-
-    def setup(self, querycontext, **kwargs):
-        pass
 
-    def create_row_processor(self, selectcontext, mapper, row):
-        return (None, None)
-
-    def do_init(self):
-        if not self.proxy:
-            return
-        class SynonymProp(object):
-            def __set__(s, obj, value):
-                setattr(obj, self.name, value)
-            def __delete__(s, obj):
-                delattr(obj, self.name)
-            def __get__(s, obj, owner):
-                if obj is None:
-                    return s
-                return getattr(obj, self.name)
-        setattr(self.parent.class_, self.key, SynonymProp())
-
-    def merge(self, session, source, dest, _recursive):
-        pass
 
 class StrategizedProperty(MapperProperty):
     """A MapperProperty which uses selectable strategies to affect
@@ -218,6 +387,46 @@ class MapperOption(object):
     def process_query(self, query):
         pass
 
+class ExtensionOption(MapperOption):
+    """a MapperOption that applies a MapperExtension to a query operation."""
+    
+    def __init__(self, ext):
+        self.ext = ext
+
+    def process_query(self, query):
+        query.extension.append(self.ext)
+
+class SynonymProperty(MapperProperty):
+    def __init__(self, name, proxy=False):
+        self.name = name
+        self.proxy = proxy
+
+    def setup(self, querycontext, **kwargs):
+        pass
+
+    def get_sub_mapper(self):
+        return self.parent.props[self.name].get_sub_mapper()
+
+    def create_row_processor(self, selectcontext, mapper, row):
+        return (None, None)
+
+    def do_init(self):
+        if not self.proxy:
+            return
+        class SynonymProp(object):
+            def __set__(s, obj, value):
+                setattr(obj, self.name, value)
+            def __delete__(s, obj):
+                delattr(obj, self.name)
+            def __get__(s, obj, owner):
+                if obj is None:
+                    return s
+                return getattr(obj, self.name)
+        setattr(self.parent.class_, self.key, SynonymProp())
+
+    def merge(self, session, source, dest, _recursive):
+        pass
+
 class PropertyOption(MapperOption):
     """A MapperOption that is applied to a property off the mapper or
     one of its child mappers, identified by a dot-separated key.
index c24de84bf541aefe7db985fbb098802fec37d219..525028b0198c46d10da93be4468d801379f54f19 100644 (file)
@@ -7,11 +7,12 @@
 from sqlalchemy import sql, schema, util, exceptions, logging
 from sqlalchemy import sql_util as sqlutil
 from sqlalchemy.orm import util as mapperutil
+from sqlalchemy.orm.util import ExtensionCarrier
 from sqlalchemy.orm import sync
-from sqlalchemy.orm.interfaces import MapperProperty, MapperOption, OperationContext
+from sqlalchemy.orm.interfaces import MapperProperty, MapperOption, OperationContext, EXT_PASS, MapperExtension
 import weakref
 
-__all__ = ['Mapper', 'MapperExtension', 'class_mapper', 'object_mapper', 'EXT_PASS', 'mapper_registry', 'ExtensionOption']
+__all__ = ['Mapper', 'class_mapper', 'object_mapper', 'mapper_registry']
 
 # a dictionary mapping classes to their primary mappers
 mapper_registry = weakref.WeakKeyDictionary()
@@ -24,8 +25,6 @@ global_extensions = []
 # column
 NO_ATTRIBUTE = object()
 
-# returned by a MapperExtension method to indicate a "do nothing" response
-EXT_PASS = object()
 
 # lock used to synchronize the "mapper compile" step
 _COMPILE_MUTEX = util.threading.Lock()
@@ -409,7 +408,7 @@ class Mapper(object):
             for ext_obj in util.to_list(extension):
                 extlist.add(ext_obj)
 
-        self.extension = _ExtensionCarrier()
+        self.extension = ExtensionCarrier()
         for ext in extlist:
             self.extension.append(ext)
 
@@ -1609,248 +1608,7 @@ class Mapper(object):
 Mapper.logger = logging.class_logger(Mapper)
 
 
-class MapperExtension(object):
-    """Base implementation for an object that provides overriding
-    behavior to various Mapper functions.  For each method in
-    MapperExtension, a result of EXT_PASS indicates the functionality
-    is not overridden.
-    """
-
-    def init_instance(self, mapper, class_, instance, args, kwargs):
-        return EXT_PASS
-
-    def init_failed(self, mapper, class_, instance, args, kwargs):
-        return EXT_PASS
-
-    def get_session(self):
-        """Retrieve a contextual Session instance with which to
-        register a new object.
-
-        Note: this is not called if a session is provided with the
-        `__init__` params (i.e. `_sa_session`).
-        """
-
-        return EXT_PASS
-
-    def load(self, query, *args, **kwargs):
-        """Override the `load` method of the Query object.
-
-        The return value of this method is used as the result of
-        ``query.load()`` if the value is anything other than EXT_PASS.
-        """
-
-        return EXT_PASS
-
-    def get(self, query, *args, **kwargs):
-        """Override the `get` method of the Query object.
-
-        The return value of this method is used as the result of
-        ``query.get()`` if the value is anything other than EXT_PASS.
-        """
-
-        return EXT_PASS
-
-    def get_by(self, query, *args, **kwargs):
-        """Override the `get_by` method of the Query object.
-
-        The return value of this method is used as the result of
-        ``query.get_by()`` if the value is anything other than
-        EXT_PASS.
-        """
-
-        return EXT_PASS
-
-    def select_by(self, query, *args, **kwargs):
-        """Override the `select_by` method of the Query object.
-
-        The return value of this method is used as the result of
-        ``query.select_by()`` if the value is anything other than
-        EXT_PASS.
-        """
-
-        return EXT_PASS
-
-    def select(self, query, *args, **kwargs):
-        """Override the `select` method of the Query object.
-
-        The return value of this method is used as the result of
-        ``query.select()`` if the value is anything other than
-        EXT_PASS.
-        """
-
-        return EXT_PASS
-
-
-    def translate_row(self, mapper, context, row):
-        """Perform pre-processing on the given result row and return a
-        new row instance.
-
-        This is called as the very first step in the ``_instance()``
-        method.
-        """
-
-        return EXT_PASS
-
-    def create_instance(self, mapper, selectcontext, row, class_):
-        """Receive a row when a new object instance is about to be
-        created from that row.
-
-        The method can choose to create the instance itself, or it can
-        return None to indicate normal object creation should take
-        place.
-
-        mapper
-          The mapper doing the operation
-
-        selectcontext
-          SelectionContext corresponding to the instances() call
-
-        row
-          The result row from the database
-
-        class\_
-          The class we are mapping.
-        """
-
-        return EXT_PASS
-
-    def append_result(self, mapper, selectcontext, row, instance, result, **flags):
-        """Receive an object instance before that instance is appended
-        to a result list.
-
-        If this method returns EXT_PASS, result appending will proceed
-        normally.  if this method returns any other value or None,
-        result appending will not proceed for this instance, giving
-        this extension an opportunity to do the appending itself, if
-        desired.
-
-        mapper
-          The mapper doing the operation.
-
-        selectcontext
-          SelectionContext corresponding to the instances() call.
-
-        row
-          The result row from the database.
-
-        instance
-          The object instance to be appended to the result.
-
-        result
-          List to which results are being appended.
-
-        \**flags
-          extra information about the row, same as criterion in
-          `create_row_processor()` method of [sqlalchemy.orm.interfaces#MapperProperty]
-        """
-
-        return EXT_PASS
-
-    def populate_instance(self, mapper, selectcontext, row, instance, **flags):
-        """Receive a newly-created instance before that instance has
-        its attributes populated.
-
-        The normal population of attributes is according to each
-        attribute's corresponding MapperProperty (which includes
-        column-based attributes as well as relationships to other
-        classes).  If this method returns EXT_PASS, instance
-        population will proceed normally.  If any other value or None
-        is returned, instance population will not proceed, giving this
-        extension an opportunity to populate the instance itself, if
-        desired.
-        """
-
-        return EXT_PASS
-
-    def before_insert(self, mapper, connection, instance):
-        """Receive an object instance before that instance is INSERTed
-        into its table.
-
-        This is a good place to set up primary key values and such
-        that aren't handled otherwise.
-        """
-
-        return EXT_PASS
-
-    def before_update(self, mapper, connection, instance):
-        """Receive an object instance before that instance is UPDATEed."""
-
-        return EXT_PASS
-
-    def after_update(self, mapper, connection, instance):
-        """Receive an object instance after that instance is UPDATEed."""
-
-        return EXT_PASS
-
-    def after_insert(self, mapper, connection, instance):
-        """Receive an object instance after that instance is INSERTed."""
-
-        return EXT_PASS
-
-    def before_delete(self, mapper, connection, instance):
-        """Receive an object instance before that instance is DELETEed."""
-
-        return EXT_PASS
 
-    def after_delete(self, mapper, connection, instance):
-        """Receive an object instance after that instance is DELETEed."""
-
-        return EXT_PASS
-
-class _ExtensionCarrier(MapperExtension):
-    def __init__(self):
-        self.__elements = []
-
-    def __iter__(self):
-        return iter(self.__elements)
-
-    def insert(self, extension):
-        """Insert a MapperExtension at the beginning of this ExtensionCarrier's list."""
-
-        self.__elements.insert(0, extension)
-
-    def append(self, extension):
-        """Append a MapperExtension at the end of this ExtensionCarrier's list."""
-
-        self.__elements.append(extension)
-        
-    def _create_do(funcname):
-        def _do(self, *args, **kwargs):
-            for elem in self.__elements:
-                ret = getattr(elem, funcname)(*args, **kwargs)
-                if ret is not EXT_PASS:
-                    return ret
-            else:
-                return EXT_PASS
-        return _do
-    
-    init_instance = _create_do('init_instance')
-    init_failed = _create_do('init_failed')
-    dispose_class = _create_do('dispose_class')
-    get_session = _create_do('get_session')
-    load = _create_do('load')
-    get = _create_do('get')
-    get_by = _create_do('get_by')
-    select_by = _create_do('select_by')
-    select = _create_do('select')
-    translate_row = _create_do('translate_row')
-    create_instance = _create_do('create_instance')
-    append_result = _create_do('append_result')
-    populate_instance = _create_do('populate_instance')
-    before_insert = _create_do('before_insert')
-    before_update = _create_do('before_update')
-    after_update = _create_do('after_update')
-    after_insert = _create_do('after_insert')
-    before_delete = _create_do('before_delete')
-    after_delete = _create_do('after_delete')
-
-
-class ExtensionOption(MapperOption):
-    def __init__(self, ext):
-        self.ext = ext
-
-    def process_query(self, query):
-        query.extension.append(self.ext)
 
 class ClassKey(object):
     """Key a class and an entity name to a mapper, via the mapper_registry."""
index 5e65fffb389ec5cd00cb4751c8ff359a20b7ae78..b5b8f830699bec0c4ceb675c6180ae23c1accd6f 100644 (file)
@@ -18,6 +18,8 @@ from sqlalchemy.orm import util as mapperutil
 import sets, random
 from sqlalchemy.orm.interfaces import *
 
+__all__ = ['ColumnProperty', 'PropertyLoader', 'BackRef']
+
 class ColumnProperty(StrategizedProperty):
     """Describes an object attribute that corresponds to a table column."""
 
@@ -38,6 +40,9 @@ class ColumnProperty(StrategizedProperty):
         else:
             return strategies.ColumnLoader(self)
 
+    def get_sub_mapper(self):
+        return None
+
     def getattr(self, object):
         return getattr(object, self.key)
 
@@ -57,6 +62,8 @@ ColumnProperty.logger = logging.class_logger(ColumnProperty)
 
 mapper.ColumnProperty = ColumnProperty
 
+        
+        
 class PropertyLoader(StrategizedProperty):
     """Describes an object property that holds a single item or list
     of items that correspond to a related database table.
@@ -109,6 +116,9 @@ class PropertyLoader(StrategizedProperty):
 
     private = property(lambda s:s.cascade.delete_orphan)
 
+    def get_sub_mapper(self):
+        return self.mapper
+
     def create_strategy(self):
         if self.lazy:
             return strategies.LazyLoader(self)
index 81dbe07b8a400875ebf49c1dc22bc83b98ef6bbd..2a93bd5d22177a921545ad203acaac5f4aeb8f9e 100644 (file)
@@ -7,6 +7,7 @@
 from sqlalchemy import sql, util, exceptions, sql_util, logging, schema
 from sqlalchemy.orm import mapper, class_mapper, object_mapper
 from sqlalchemy.orm.interfaces import OperationContext, SynonymProperty
+from sqlalchemy.orm.util import ExtensionCarrier
 
 __all__ = ['Query', 'QueryContext', 'SelectionContext']
 
@@ -22,7 +23,7 @@ class Query(object):
         self.select_mapper = self.mapper.get_select_mapper().compile()
         self.always_refresh = kwargs.pop('always_refresh', self.mapper.always_refresh)
         self.lockmode = lockmode
-        self.extension = mapper._ExtensionCarrier()
+        self.extension = ExtensionCarrier()
         if extension is not None:
             self.extension.append(extension)
         self.extension.append(self.mapper.extension)
@@ -59,9 +60,7 @@ class Query(object):
         q._session = self.session
         q.is_polymorphic = self.is_polymorphic
         q.lockmode = self.lockmode
-        q.extension = mapper._ExtensionCarrier()
-        for ext in self.extension:
-            q.extension.append(ext)
+        q.extension = self.extension.copy()
         q._offset = self._offset
         q._limit = self._limit
         q._group_by = self._group_by
index 6b3585598919ed023f393c2fb620f80190a8d775..a3184d62b5170de212d0b81a7ed5be74b3793089 100644 (file)
@@ -7,7 +7,7 @@
 """sqlalchemy.orm.interfaces.LoaderStrategy implementations, and related MapperOptions."""
 
 from sqlalchemy import sql, schema, util, exceptions, sql_util, logging
-from sqlalchemy.orm import mapper, query
+from sqlalchemy.orm import mapper
 from sqlalchemy.orm.interfaces import *
 from sqlalchemy.orm.attributes import InstrumentedAttribute
 from sqlalchemy.orm import session as sessionlib
@@ -237,6 +237,7 @@ class LazyLoader(AbstractRelationLoader):
 
         # determine if our "lazywhere" clause is the same as the mapper's
         # get() clause.  then we can just use mapper.get()
+        from sqlalchemy.orm import query
         self.use_get = not self.uselist and query.Query(self.mapper)._get_clause.compare(self.lazywhere)
         if self.use_get:
             self.logger.info(str(self.parent_property) + " will use query.get() to optimize instance loads")
index e80d954bd972890e66f39ec58c359a7d710f32da..a148dc6afa115fe3c7ffc3958f54d05ba3f49f02 100644 (file)
@@ -5,6 +5,7 @@
 # the MIT License: http://www.opensource.org/licenses/mit-license.php
 
 from sqlalchemy import sql, util, exceptions
+from sqlalchemy.orm.interfaces import MapperExtension, EXT_PASS
 
 all_cascades = util.Set(["delete", "delete-orphan", "all", "merge",
                          "expunge", "save-update", "refresh-expire", "none"])
@@ -109,6 +110,56 @@ class TranslatingDict(dict):
     def setdefault(self, col, value):
         return super(TranslatingDict, self).setdefault(self.__translate_col(col), value)
 
+class ExtensionCarrier(MapperExtension):
+    def __init__(self, _elements=None):
+        self.__elements = _elements or []
+
+    def copy(self):
+        return ExtensionCarrier(list(self.__elements))
+        
+    def __iter__(self):
+        return iter(self.__elements)
+
+    def insert(self, extension):
+        """Insert a MapperExtension at the beginning of this ExtensionCarrier's list."""
+
+        self.__elements.insert(0, extension)
+
+    def append(self, extension):
+        """Append a MapperExtension at the end of this ExtensionCarrier's list."""
+
+        self.__elements.append(extension)
+
+    def _create_do(funcname):
+        def _do(self, *args, **kwargs):
+            for elem in self.__elements:
+                ret = getattr(elem, funcname)(*args, **kwargs)
+                if ret is not EXT_PASS:
+                    return ret
+            else:
+                return EXT_PASS
+        return _do
+
+    init_instance = _create_do('init_instance')
+    init_failed = _create_do('init_failed')
+    dispose_class = _create_do('dispose_class')
+    get_session = _create_do('get_session')
+    load = _create_do('load')
+    get = _create_do('get')
+    get_by = _create_do('get_by')
+    select_by = _create_do('select_by')
+    select = _create_do('select')
+    translate_row = _create_do('translate_row')
+    create_instance = _create_do('create_instance')
+    append_result = _create_do('append_result')
+    populate_instance = _create_do('populate_instance')
+    before_insert = _create_do('before_insert')
+    before_update = _create_do('before_update')
+    after_update = _create_do('after_update')
+    after_insert = _create_do('after_insert')
+    before_delete = _create_do('before_delete')
+    after_delete = _create_do('after_delete')
+
 class BinaryVisitor(sql.ClauseVisitor):
     def __init__(self, func):
         self.func = func
index 755f6cf8908d802b473495d7000c69588d6189a2..c751ac8a1701f1957586d4f0ed46e930e4b7fceb 100644 (file)
@@ -1,6 +1,7 @@
 import testbase
 
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 
 class AssociationTest(testbase.PersistTest):
index 7cb1231608bf6bd0eec735e45243885a2af5281f..80b846c68235dd8bbdcf114eacf7bbd5cd441622 100644 (file)
@@ -3,6 +3,7 @@ import unittest, sys, datetime
 
 from sqlalchemy.ext.sessioncontext import SessionContext
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 class O2MCascadeTest(testbase.AssertMixin):
     def tearDown(self):
index 96e56e59728de639b9d48b1c50ac9612b7c684f3..604c75d4882b9a2209281247b0f22f0857e40ae5 100644 (file)
@@ -1,5 +1,7 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 
 class CompileTest(testbase.AssertMixin):
     """test various mapper compilation scenarios"""
index d02a8c8d2df3cf59ca201235f0b59780684ae54d..dc086b635b845b9f1a6f4015fda84b4b32948821 100644 (file)
@@ -1,6 +1,7 @@
 from testbase import PersistTest, AssertMixin, ORMTest
 import unittest, sys, os
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import StringIO
 import testbase
 
index 9765379f4bca023c5ccbe5ae84d36d7229b5d7ee..da94c782ab0581934fee93b63d1ab787f1ded062 100644 (file)
@@ -2,6 +2,7 @@ from testbase import PersistTest, AssertMixin
 import testbase
 import unittest, sys, os
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import datetime
 
 class EagerTest(AssertMixin):
index 78e1d987072751cece645ab8baa5889d51c40e08..e7bc4c2cb086f97423de3a4f944b59d71eb5e120 100644 (file)
@@ -2,6 +2,7 @@ from testbase import PersistTest, AssertMixin
 import testbase
 import unittest, sys, os
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import datetime
 from sqlalchemy.ext.sessioncontext import SessionContext
 
index c92444dd61cc58586754e9f84797cd046f920242..0a55a1b56a43957129b8055a6af92d6c4b2b8a2b 100644 (file)
@@ -1,6 +1,7 @@
 from testbase import PersistTest, AssertMixin
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 from sqlalchemy.ext.selectresults import SelectResults
 import random
 
index 202964a6985c38a1aac287ea669197ab10480fb1..4fc15fef16f1838c3de0704aa518dd09164a0d15 100644 (file)
@@ -1,6 +1,7 @@
 from testbase import PersistTest, AssertMixin
 import unittest
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import testbase
 from sqlalchemy.ext.sessioncontext import SessionContext
 
index bda34ba1c8253f8bf9a084d7f804048c7dac160c..a64277e2efa5d7c7d43404b129ac72523241eb03 100644 (file)
@@ -3,6 +3,7 @@ import testbase
 import tables
 
 from sqlalchemy import *
+from sqlalchemy.orm import *
 from sqlalchemy import exceptions
 
 class Foo(object):
index 89a7cfc3e52e61be0408c1de8bf740e225331643..d85ac39c71ece2887ce879b96886b489beeb5438 100644 (file)
@@ -1,4 +1,6 @@
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 from sqlalchemy.orm.sync import ONETOMANY, MANYTOONE
 import testbase
 
index f95390008e383d25bb372f88dc3eae58fe413dc7..d8ae77408178d51df0396e3a561d0f4f11ee1e14 100644 (file)
@@ -1,5 +1,6 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 
 class O2MTest(testbase.ORMTest):
index 9f4e275ae2df86a12dc80bce9f778b3a21cf57b9..af5b7da0ea7871a3372bcfe7739138c221fdc106 100644 (file)
@@ -1,4 +1,5 @@
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import testbase
 
 class ConcreteTest1(testbase.ORMTest):
index 9a52919dd7681f739f6027e6d51befede1aa96b8..20270d59cb5a560dab718383ab11aa74524c7f1f 100644 (file)
@@ -1,5 +1,7 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 
 class BaseObject(object):
     def __init__(self, *args, **kwargs):
index b5cc83e7b4c26e80f7d45aeeaa2fd2cc53025017..9571ccf2fc5a15b303a3c55fb6b28f53937b2b71 100644 (file)
@@ -1,5 +1,6 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 
 class InheritTest(testbase.ORMTest):
index 30cda4bb6a2b2e2cfd2e370367afdee7cd125e46..406981e7a43fa2d268585c15aa888455234f7a1a 100644 (file)
@@ -1,5 +1,6 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 class PolymorphicCircularTest(testbase.ORMTest):
     keep_mappers = True
index 1ff608d24e66939bd8499dde9bbb4c27acd677f2..7b14378bc57109daf14563fa7db1c8781d31be14 100644 (file)
@@ -1,5 +1,7 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 import sets
 
 # tests basic polymorphic mapper loading/saving, minimal relations
index bd95d4ff23fc1548f95f7aad8881bc7c1d3d074a..fbcdb5131a02daac2e53fa37075b07dc17281dad 100644 (file)
@@ -1,4 +1,6 @@
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 import testbase
 
 class AttrSettable(object):
index 90652645665060b852413c93b14ab76667cf6537..510f9ec8b6ebfbe82c857703d5c8305060432a7b 100644 (file)
@@ -1,5 +1,7 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 from datetime import datetime
 
 class InheritTest(testbase.ORMTest):
index d78084fe1180dd9bfb373659db9fe5971cbc5de6..87ee0e57c0b46f138d246444b7f2bcec2bc6409d 100644 (file)
@@ -1,4 +1,6 @@
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 import testbase
 
 class SingleInheritanceTest(testbase.AssertMixin):
index 9f2d53e9d0bc1f2b205f3202458cfe8861a29015..0a88785cda8ce4ba5f76e8ffcc56345f2b336333 100644 (file)
@@ -2,6 +2,7 @@ from testbase import PersistTest, AssertMixin
 import testbase
 import unittest, sys, os
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import datetime
 
 class LazyTest(AssertMixin):
index f6e9197a2c0532e381d1e200cf3343072123e558..01df54d8164d5ad653b9068ee19c858636060606 100644 (file)
@@ -1,5 +1,6 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import string
 
 class Place(object):
index 0b8ca19910e866ff17c87c96548b31a49073aa27..34d0c81e473856660f067d11a8e4ea345732ee54 100644 (file)
@@ -2,6 +2,7 @@ from testbase import PersistTest, AssertMixin
 import testbase
 import unittest, sys, os
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import sqlalchemy.exceptions as exceptions
 from sqlalchemy.ext.sessioncontext import SessionContext, SessionContextExt
 from tables import *
index b456a1abbc715b562d4167f56122519e28a74d09..e53890d69fecb0e5525a467fe14cb363340f7f39 100644 (file)
@@ -1,4 +1,5 @@
 from sqlalchemy import *
+from sqlalchemy.orm import *
 from sqlalchemy.orm import mapperlib, session, unitofwork, attributes
 Mapper = mapperlib.Mapper
 import gc
index cca01f2a564577c99d9356ab580e4eaa941f088b..41a755afb4ef67d117187f6f0defad72fbd60d43 100644 (file)
@@ -1,6 +1,7 @@
 from testbase import PersistTest, AssertMixin
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 from tables import *
 import tables
 
index 525c8db7e88a2003355e0df04b46d172f4f0d162..e78eddb093babf793d36c294b5ee9a387b089a4f 100644 (file)
@@ -1,5 +1,6 @@
 import testbase
 from sqlalchemy import *
+from sqlalchemy.orm import *
 from sqlalchemy.ext.sessioncontext import SessionContext
 
 class Jack(object):
index 5f53af080f5754a2d9de18b712b357637e8d7f0a..e5fd0dd328649e7844831b34a04357eacbdb7c34 100644 (file)
@@ -5,6 +5,7 @@ db = testbase.db
 #db. 
 
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 
 class RelationTest(testbase.PersistTest):
index d659d834bd2ff47318b05117577749ade2902d6e..cf0b6d5d8a715f0f31925dbb6de81f4064253e1a 100644 (file)
@@ -7,6 +7,7 @@ from tables import *
 
 db = testbase.db
 from sqlalchemy import *
+from sqlalchemy.orm import *
 
 
 class SessionTest(AssertMixin):
index 83bc2f2bf96a0a987def1576163ce4d4bbfe96a2..57615ed5833b7ea7c8759a179f295bb53aee0119 100644 (file)
@@ -3,6 +3,8 @@ import unittest, sys, os
 from sqlalchemy.ext.sessioncontext import SessionContext
 from sqlalchemy.orm.session import object_session, Session
 from sqlalchemy import *
+from sqlalchemy.orm import *
+
 import testbase
 
 metadata = MetaData()
index 62b1db8604124023a0bfc0f0b1569382e42a986c..e89c0f9a850e42a776e4717eb805d250b2b7c2dc 100644 (file)
@@ -1,5 +1,6 @@
 from testbase import PersistTest, AssertMixin
 from sqlalchemy import *
+from sqlalchemy.orm import *
 import testbase
 import pickleable
 from sqlalchemy.orm.mapper import global_extensions