From b0991bf661964b3d1cafc4cf0ae4649e14f9b5ea Mon Sep 17 00:00:00 2001 From: Jason Kirtland Date: Wed, 6 Feb 2008 01:09:08 +0000 Subject: [PATCH] - A few quick docstring typo fixes, including [ticket:766] --- lib/sqlalchemy/orm/__init__.py | 267 +++++++++++++++--------------- lib/sqlalchemy/orm/collections.py | 12 +- lib/sqlalchemy/orm/interfaces.py | 253 ++++++++++++++-------------- lib/sqlalchemy/orm/mapper.py | 26 +-- lib/sqlalchemy/orm/query.py | 42 ++--- 5 files changed, 302 insertions(+), 298 deletions(-) diff --git a/lib/sqlalchemy/orm/__init__.py b/lib/sqlalchemy/orm/__init__.py index 9201866e82..eb92988ff7 100644 --- a/lib/sqlalchemy/orm/__init__.py +++ b/lib/sqlalchemy/orm/__init__.py @@ -7,7 +7,7 @@ """ Functional constructs for ORM configuration. -See the SQLAlchemy object relational tutorial and mapper configuration +See the SQLAlchemy object relational tutorial and mapper configuration documentation for an overview of how this module is used. """ @@ -37,7 +37,7 @@ __all__ = [ 'relation', 'column_property', 'composite', 'backref', 'eagerload', def scoped_session(session_factory, scopefunc=None): """Provides thread-local management of Sessions. - + This is a front-end function to the [sqlalchemy.orm.scoping#ScopedSession] class. @@ -47,44 +47,44 @@ def scoped_session(session_factory, scopefunc=None): To instantiate a Session object which is part of the scoped context, instantiate normally:: - + session = Session() - + Most session methods are available as classmethods from the scoped session:: - + Session.commit() Session.close() - + To map classes so that new instances are saved in the current Session automatically, as well as to provide session-aware class attributes such as "query", use the `mapper` classmethod from the scoped session:: - + mapper = Session.mapper mapper(Class, table, ...) """ - + return ScopedSession(session_factory, scopefunc=scopefunc) - + def create_session(bind=None, **kwargs): """create a new [sqlalchemy.orm.session#Session]. - + The session by default does not begin a transaction, and requires that flush() be called explicitly in order to persist results to the database. - - It is recommended to use the [sqlalchemy.orm#sessionmaker()] function + + It is recommended to use the [sqlalchemy.orm#sessionmaker()] function instead of create_session(). """ kwargs.setdefault('autoflush', False) kwargs.setdefault('transactional', False) return _Session(bind=bind, **kwargs) - + def relation(argument, secondary=None, **kwargs): """Provide a relationship of a primary Mapper to a secondary Mapper. - This corresponds to a parent-child or associative table relationship. + This corresponds to a parent-child or associative table relationship. The constructed class is an instance of [sqlalchemy.orm.properties#PropertyLoader]. argument @@ -101,28 +101,28 @@ def relation(argument, secondary=None, **kwargs): \**kwargs follow: association - Deprecated; as of version 0.3.0 the association keyword is synonomous + Deprecated; as of version 0.3.0 the association keyword is synonymous with applying the "all, delete-orphan" cascade to a "one-to-many" relationship. SA can now automatically reconcile a "delete" and "insert" operation of two objects with the same "identity" in a flush() operation into a single "update" statement, which is the pattern that - "association" used to indicate. - + "association" used to indicate. + backref indicates the name of a property to be placed on the related mapper's class that will handle this relationship in the other direction, including synchronizing the object attributes on both sides of the relation. Can also point to a ``backref()`` construct for more - configurability. - + configurability. + cascade a string list of cascade rules which determines how persistence - operations should be "cascaded" from parent to child. - + operations should be "cascaded" from parent to child. + collection_class a class or function that returns a new list-holding object. will be - used in place of a plain list for storing elements. - + used in place of a plain list for storing elements. + foreign_keys a list of columns which are to be used as "foreign key" columns. this parameter should be used in conjunction with explicit @@ -143,36 +143,36 @@ def relation(argument, secondary=None, **kwargs): deep eagerload joins should be constructed on a self-referring or cyclical relationship. The number counts how many times the same Mapper shall be present in the loading condition along - a particular join branch. When left at its default of ``None``, - eager loads will automatically stop chaining joins when they encounter + a particular join branch. When left at its default of ``None``, + eager loads will automatically stop chaining joins when they encounter a mapper which is already higher up in the chain. - + lazy=(True|False|None|'dynamic') specifies how the related items should be loaded. Values include: - + True - items should be loaded lazily when the property is first - accessed. - - False - items should be loaded "eagerly" in the same query as that + accessed. + + False - items should be loaded "eagerly" in the same query as that of the parent, using a JOIN or LEFT OUTER JOIN. - + None - no loading should occur at any time. This is to support - "write-only" attrbitutes, or attributes which are populated in + "write-only" attributes, or attributes which are populated in some manner specific to the application. - + 'dynamic' - a ``DynaLoader`` will be attached, which returns a ``Query`` object for all read operations. The dynamic- collection supports only ``append()`` and ``remove()`` - for write operations; changes to the dynamic property - will not be visible until the data is flushed to the - database. + for write operations; changes to the dynamic property + will not be visible until the data is flushed to the + database. order_by indicates the ordering that should be applied when loading these items. passive_deletes=False - Indicates loading behavior during delete operations. - + Indicates loading behavior during delete operations. + A value of True indicates that unloaded child items should not be loaded during a delete operation on the parent. Normally, when a parent item is deleted, all child items are loaded so that they can either be @@ -180,51 +180,55 @@ def relation(argument, secondary=None, **kwargs): Marking this flag as True usually implies an ON DELETE rule is in place which will handle updating/deleting child rows on the database side. - + Additionally, setting the flag to the string value 'all' will disable the "nulling out" of the child foreign keys, when there is no delete or delete-orphan cascade enabled. This is typically used when a triggering or error raise scenario is in place on the database side. Note that the foreign key attributes on in-session child objects will not be changed after a flush occurs so this is a very special use-case setting. - + passive_updates=True Indicates loading and INSERT/UPDATE/DELETE behavior when the source - of a foreign key value changes (i.e. an "on update" cascade), which are - typically the primary key columns of the source row. - + of a foreign key value changes (i.e. an "on update" cascade), which + are typically the primary key columns of the source row. + When True, it is assumed that ON UPDATE CASCADE is configured on the - foreign key in the database, and that the database will handle propagation of an - UPDATE from a source column to dependent rows. Note that with databases - which enforce referential integrity (ie. Postgres, MySQL with InnoDB tables), - ON UPDATE CASCADE is required for this operation. The relation() will - update the value of the attribute on related items which are locally present - in the session during a flush. - - When False, it is assumed that the database does not enforce referential - integrity and will not be issuing its own CASCADE operation for an update. - The relation() will issue the appropriate UPDATE statements to the database - in response to the change of a referenced key, and items locally present - in the session during a flush will also be refreshed. - - This flag should probably be set to False if primary key changes are expected - and the database in use doesn't support CASCADE (i.e. SQLite, MySQL MyISAM tables). - + foreign key in the database, and that the database will handle + propagation of an UPDATE from a source column to dependent rows. + Note that with databases which enforce referential integrity + (i.e. Postgres, MySQL with InnoDB tables), ON UPDATE CASCADE is + required for this operation. The relation() will update the value + of the attribute on related items which are locally present in the + session during a flush. + + When False, it is assumed that the database does not enforce + referential integrity and will not be issuing its own CASCADE + operation for an update. The relation() will issue the appropriate + UPDATE statements to the database in response to the change of a + referenced key, and items locally present in the session during a + flush will also be refreshed. + + This flag should probably be set to False if primary key changes are + expected and the database in use doesn't support CASCADE + (i.e. SQLite, MySQL MyISAM tables). + post_update this indicates that the relationship should be handled by a second - UPDATE statement after an INSERT or before a DELETE. Currently, it also - will issue an UPDATE after the instance was UPDATEd as well, although - this technically should be improved. This flag is used to handle saving - bi-directional dependencies between two individual rows (i.e. each row - references the other), where it would otherwise be impossible to INSERT - or DELETE both rows fully since one row exists before the other. Use - this flag when a particular mapping arrangement will incur two rows - that are dependent on each other, such as a table that has a - one-to-many relationship to a set of child rows, and also has a column - that references a single child row within that list (i.e. both tables - contain a foreign key to each other). If a ``flush()`` operation returns - an error that a "cyclical dependency" was detected, this is a cue that - you might want to use ``post_update`` to "break" the cycle. + UPDATE statement after an INSERT or before a DELETE. Currently, it + also will issue an UPDATE after the instance was UPDATEd as well, + although this technically should be improved. This flag is used to + handle saving bi-directional dependencies between two individual + rows (i.e. each row references the other), where it would otherwise + be impossible to INSERT or DELETE both rows fully since one row + exists before the other. Use this flag when a particular mapping + arrangement will incur two rows that are dependent on each other, + such as a table that has a one-to-many relationship to a set of + child rows, and also has a column that references a single child row + within that list (i.e. both tables contain a foreign key to each + other). If a ``flush()`` operation returns an error that a "cyclical + dependency" was detected, this is a cue that you might want to use + ``post_update`` to "break" the cycle. primaryjoin a ClauseElement that will be used as the primary join of this child @@ -236,11 +240,11 @@ def relation(argument, secondary=None, **kwargs): private=False deprecated. setting ``private=True`` is the equivalent of setting ``cascade="all, delete-orphan"``, and indicates the lifecycle of child - objects should be contained within that of the parent. + objects should be contained within that of the parent. remote_side used for self-referential relationships, indicates the column or list - of columns that form the "remote side" of the relationship. + of columns that form the "remote side" of the relationship. secondaryjoin a ClauseElement that will be used as the join of an association table @@ -268,26 +272,26 @@ def relation(argument, secondary=None, **kwargs): return PropertyLoader(argument, secondary=secondary, **kwargs) -def dynamic_loader(argument, secondary=None, primaryjoin=None, secondaryjoin=None, entity_name=None, +def dynamic_loader(argument, secondary=None, primaryjoin=None, secondaryjoin=None, entity_name=None, foreign_keys=None, backref=None, post_update=False, cascade=None, remote_side=None, enable_typechecks=True, passive_deletes=False): """construct a dynamically-loading mapper property. - + This property is similar to relation(), except read operations - return an active Query object, which reads from the database in all + return an active Query object, which reads from the database in all cases. Items may be appended to the attribute via append(), or removed via remove(); changes will be persisted to the database during a flush(). However, no other list mutation operations are available. - + A subset of arguments available to relation() are available here. """ from sqlalchemy.orm.strategies import DynaLoader - - return PropertyLoader(argument, secondary=secondary, primaryjoin=primaryjoin, - secondaryjoin=secondaryjoin, entity_name=entity_name, foreign_keys=foreign_keys, backref=backref, - post_update=post_update, cascade=cascade, remote_side=remote_side, enable_typechecks=enable_typechecks, + + return PropertyLoader(argument, secondary=secondary, primaryjoin=primaryjoin, + secondaryjoin=secondaryjoin, entity_name=entity_name, foreign_keys=foreign_keys, backref=backref, + post_update=post_update, cascade=cascade, remote_side=remote_side, enable_typechecks=enable_typechecks, passive_deletes=passive_deletes, strategy_class=DynaLoader) @@ -302,28 +306,28 @@ def column_property(*args, **kwargs): the mapper's selectable; examples include SQL expressions, functions, and scalar SELECT queries. - Columns that arent present in the mapper's selectable won't be persisted + Columns that aren't present in the mapper's selectable won't be persisted by the mapper and are effectively "read-only" attributes. \*cols list of Column objects to be mapped. - + group a group name for this property when marked as deferred. - + deferred when True, the column property is "deferred", meaning that it does not load immediately, and is instead loaded when the - attribute is first accessed on an instance. See also + attribute is first accessed on an instance. See also [sqlalchemy.orm#deferred()]. """ - + return ColumnProperty(*args, **kwargs) def composite(class_, *cols, **kwargs): """Return a composite column-based property for use with a Mapper. - + This is very much like a column-based property except the given class is used to represent "composite" values composed of one or more columns. @@ -345,30 +349,30 @@ def composite(class_, *cols, **kwargs): ... composite(Point, mytable.c.x, mytable.c.y) ... Arguments are: - + class\_ The "composite type" class. - + \*cols List of Column objects to be mapped. - + group A group name for this property when marked as deferred. - + deferred When True, the column property is "deferred", meaning that it does not load immediately, and is instead loaded when the - attribute is first accessed on an instance. See also + attribute is first accessed on an instance. See also [sqlalchemy.orm#deferred()]. - + comparator An optional instance of [sqlalchemy.orm#PropComparator] which provides SQL expression generation functions for this composite type. """ - + return CompositeProperty(class_, *cols, **kwargs) - + def backref(name, **kwargs): """Create a BackRef object with explicit arguments, which are the same arguments one @@ -410,7 +414,7 @@ def mapper(class_, local_table=None, *args, **params): overwrite all data within object instances that already exist within the session, erasing any in-memory changes with whatever information was loaded from the database. Usage - of this flag is highly discouraged; as an alternative, + of this flag is highly discouraged; as an alternative, see the method `populate_existing()` on [sqlalchemy.orm.query#Query]. allow_column_override @@ -460,9 +464,9 @@ def mapper(class_, local_table=None, *args, **params): inherit_foreign_keys when inherit_condition is used and the condition contains no - ForeignKey columns, specify the "foreign" columns of the join + ForeignKey columns, specify the "foreign" columns of the join condition in this list. else leave as None. - + order_by A single ``Column`` or list of ``Columns`` for which selection operations should use as the default ordering for @@ -482,7 +486,7 @@ def mapper(class_, local_table=None, *args, **params): hierarchy. _polymorphic_map - Used internally to propigate the full map of polymorphic + Used internally to propagate the full map of polymorphic identifiers to surrogate mappers. polymorphic_identity @@ -491,9 +495,9 @@ def mapper(class_, local_table=None, *args, **params): this mapper. polymorphic_fetch - specifies how subclasses mapped through joined-table - inheritance will be fetched. options are 'union', - 'select', and 'deferred'. if the select_table argument + specifies how subclasses mapped through joined-table + inheritance will be fetched. options are 'union', + 'select', and 'deferred'. if the select_table argument is present, defaults to 'union', otherwise defaults to 'select'. @@ -527,9 +531,9 @@ def mapper(class_, local_table=None, *args, **params): can be overridden here. select_table - A [sqlalchemy.schema#Table] or any [sqlalchemy.sql#Selectable] - which will be used to select instances of this mapper's class. - usually used to provide polymorphic loading among several + A [sqlalchemy.schema#Table] or any [sqlalchemy.sql#Selectable] + which will be used to select instances of this mapper's class. + usually used to provide polymorphic loading among several classes in an inheritance hierarchy. version_id_col @@ -547,42 +551,42 @@ def synonym(name, map_column=False, proxy=False): """Set up `name` as a synonym to another mapped property. Used with the ``properties`` dictionary sent to [sqlalchemy.orm#mapper()]. - + Any existing attributes on the class which map the key name sent - to the ``properties`` dictionary will be used by the synonym to + to the ``properties`` dictionary will be used by the synonym to provide instance-attribute behavior (that is, any Python property object, - provided by the ``property`` builtin or providing a ``__get__()``, + provided by the ``property`` builtin or providing a ``__get__()``, ``__set__()`` and ``__del__()`` method). If no name exists for the key, the ``synonym()`` creates a default getter/setter object automatically and applies it to the class. - + `name` refers to the name of the existing mapped property, which can be any other ``MapperProperty`` including column-based properties and relations. - - if `map_column` is ``True``, an additional ``ColumnProperty`` - is created on the mapper automatically, using the synonym's - name as the keyname of the property, and the keyname of this ``synonym()`` - as the name of the column to map. For example, if a table has a column - named ``status``:: - + + If `map_column` is ``True``, an additional ``ColumnProperty`` is created + on the mapper automatically, using the synonym's name as the keyname of + the property, and the keyname of this ``synonym()`` as the name of the + column to map. For example, if a table has a column named ``status``:: + class MyClass(object): def _get_status(self): return self._status def _set_status(self, value): self._status = value status = property(_get_status, _set_status) - + mapper(MyClass, sometable, properties={ "status":synonym("_status", map_column=True) }) - - The column named ``status`` will be mapped to the attribute named ``_status``, - and the ``status`` attribute on ``MyClass`` will be used to proxy access to the - column-based attribute. - - The `proxy` keyword argument is deprecated and currently does nothing; synonyms - now always establish an attribute getter/setter funciton if one is not already available. + + The column named ``status`` will be mapped to the attribute named + ``_status``, and the ``status`` attribute on ``MyClass`` will be used to + proxy access to the column-based attribute. + + The `proxy` keyword argument is deprecated and currently does nothing; + synonyms now always establish an attribute getter/setter function if one + is not already available. """ return SynonymProperty(name, map_column=map_column) @@ -608,7 +612,7 @@ def clear_mappers(): mapper.dispose() finally: mapperlib._COMPILE_MUTEX.release() - + def extension(ext): """Return a ``MapperOption`` that will insert the given ``MapperExtension`` to the beginning of the list of extensions @@ -629,11 +633,11 @@ def eagerload(name, mapper=None): def eagerload_all(name, mapper=None): """Return a ``MapperOption`` that will convert all properties along the given dot-separated path into an eager load. - + For example, this:: query.options(eagerload_all('orders.items.keywords'))... - + will set all of 'orders', 'orders.items', and 'orders.items.keywords' to load in one eager load. @@ -653,7 +657,7 @@ def lazyload(name, mapper=None): def fetchmode(name, type): return strategies.FetchModeOption(name, type) - + def noload(name): """Return a ``MapperOption`` that will convert the property of the given name into a non-load. @@ -699,7 +703,7 @@ def contains_eager(key, alias=None, decorator=None): Used when feeding SQL result sets directly into ``query.instances()``. Also bundles an ``EagerLazyOption`` to - turn on eager loading in case it isnt already. + turn on eager loading in case it isn't already. `alias` is the string name of an alias, **or** an ``sql.Alias`` object, which represents the aliased columns in the query. This @@ -730,10 +734,9 @@ def undefer(name): return strategies.DeferredOption(name, defer=False) def undefer_group(name): - """Return a ``MapperOption`` that will convert the given + """Return a ``MapperOption`` that will convert the given group of deferred column properties into a non-deferred (regular column) load. Used with ``query.options()``. """ return strategies.UndeferGroupOption(name) - diff --git a/lib/sqlalchemy/orm/collections.py b/lib/sqlalchemy/orm/collections.py index daf9dfb450..f2b726b4c4 100644 --- a/lib/sqlalchemy/orm/collections.py +++ b/lib/sqlalchemy/orm/collections.py @@ -31,7 +31,7 @@ standard Python ``list``, ``set`` and ``dict`` interfaces. These could be specified in terms of generic decorator recipes, but are instead hand-tooled for increased efficiency. The targeted decorators occasionally implement adapter-like behavior, such as mapping bulk-set methods (``extend``, ``update``, -``__setslice``, etc.) into the series of atomic mutation events that the ORM +``__setslice__``, etc.) into the series of atomic mutation events that the ORM requires. The targeted decorators are used internally for automatic instrumentation of @@ -587,13 +587,13 @@ class CollectionAdapter(object): def fire_pre_remove_event(self, initiator=None): """Notify that an entity is about to be removed from the collection. - - Only called if the entity cannot be removed after calling + + Only called if the entity cannot be removed after calling fire_remove_event(). """ - + self.attr.fire_pre_remove_event(self.owner_state, initiator=initiator) - + def __getstate__(self): return { 'key': self.attr.key, 'owner_state': self.owner_state, @@ -853,7 +853,7 @@ def __before_delete(collection, _sa_initiator=None): executor = getattr(collection, '_sa_adapter', None) if executor: getattr(executor, 'fire_pre_remove_event')(_sa_initiator) - + def _list_decorators(): """Hand-turned instrumentation wrappers that can decorate any list-like class.""" diff --git a/lib/sqlalchemy/orm/interfaces.py b/lib/sqlalchemy/orm/interfaces.py index d34cca7faa..aa3a42291b 100644 --- a/lib/sqlalchemy/orm/interfaces.py +++ b/lib/sqlalchemy/orm/interfaces.py @@ -11,17 +11,17 @@ Defines the [sqlalchemy.orm.interfaces#MapperExtension] class, which can be end-user subclassed to add event-based functionality to mappers. The remainder of this module is generally private to the ORM. - """ + from sqlalchemy import util, logging, exceptions from sqlalchemy.sql import expression from itertools import chain class_mapper = None __all__ = ['EXT_CONTINUE', 'EXT_STOP', 'EXT_PASS', 'MapperExtension', - 'MapperProperty', 'PropComparator', 'StrategizedProperty', - 'build_path', 'MapperOption', - 'ExtensionOption', 'PropertyOption', + 'MapperProperty', 'PropComparator', 'StrategizedProperty', + 'build_path', 'MapperOption', + 'ExtensionOption', 'PropertyOption', 'AttributeExtension', 'StrategizedOption', 'LoaderStrategy' ] EXT_CONTINUE = EXT_PASS = object() @@ -30,25 +30,23 @@ EXT_STOP = object() class MapperExtension(object): """Base implementation for customizing Mapper behavior. - For each method in MapperExtension, returning a result of - EXT_CONTINUE will allow processing to continue to the next - MapperExtension in line or use the default functionality if there - are no other extensions. - - Returning EXT_STOP will halt processing of further extensions - handling that method. Some methods such as ``load`` have other - return requirements, see the individual documentation for details. - Other than these exception cases, any return value other than - EXT_CONTINUE or EXT_STOP will be interpreted as equivalent to - EXT_STOP. - - EXT_PASS is a synonym for EXT_CONTINUE and is provided for - backward compatibility. + For each method in MapperExtension, returning a result of EXT_CONTINUE + will allow processing to continue to the next MapperExtension in line or + use the default functionality if there are no other extensions. + + Returning EXT_STOP will halt processing of further extensions handling + that method. Some methods such as ``load`` have other return + requirements, see the individual documentation for details. Other than + these exception cases, any return value other than EXT_CONTINUE or + EXT_STOP will be interpreted as equivalent to EXT_STOP. + + EXT_PASS is a synonym for EXT_CONTINUE and is provided for backward + compatibility. """ - + def instrument_class(self, mapper, class_): return EXT_CONTINUE - + def init_instance(self, mapper, class_, oldinit, instance, args, kwargs): return EXT_CONTINUE @@ -89,7 +87,7 @@ class MapperExtension(object): The return value of this method is used as the result of ``query.get_by()`` if the value is anything other than EXT_CONTINUE. - + DEPRECATED. """ @@ -101,7 +99,7 @@ class MapperExtension(object): The return value of this method is used as the result of ``query.select_by()`` if the value is anything other than EXT_CONTINUE. - + DEPRECATED. """ @@ -113,7 +111,7 @@ class MapperExtension(object): The return value of this method is used as the result of ``query.select()`` if the value is anything other than EXT_CONTINUE. - + DEPRECATED. """ @@ -134,9 +132,8 @@ class MapperExtension(object): """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 EXT_CONTINUE to indicate normal object creation should take - place. + The method can choose to create the instance itself, or it can return + EXT_CONTINUE to indicate normal object creation should take place. mapper The mapper doing the operation @@ -149,7 +146,7 @@ class MapperExtension(object): class\_ The class we are mapping. - + return value A new object instance, or EXT_CONTINUE """ @@ -211,12 +208,12 @@ class MapperExtension(object): This is a good place to set up primary key values and such that aren't handled otherwise. - Column-based attributes can be modified within this method which will - result in the new value being inserted. However *no* changes to the overall + Column-based attributes can be modified within this method which will + result in the new value being inserted. However *no* changes to the overall flush plan can be made; this means any collection modification or save() operations which occur within this method will not take effect until the next flush call. - + """ return EXT_CONTINUE @@ -228,11 +225,11 @@ class MapperExtension(object): def before_update(self, mapper, connection, instance): """Receive an object instance before that instance is UPDATEed. - - Note that this method is called for all instances that are marked as - "dirty", even those which have no net changes to their column-based + + Note that this method is called for all instances that are marked as + "dirty", even those which have no net changes to their column-based attributes. An object is marked as dirty when any of its column-based - attributes have a "set attribute" operation called or when any of its + attributes have a "set attribute" operation called or when any of its collections are modified. If, at update time, no column-based attributes have any net changes, no UPDATE statement will be issued. This means that an instance being sent to before_update is *not* a guarantee that @@ -240,15 +237,15 @@ class MapperExtension(object): here). To detect if the column-based attributes on the object have net changes, - and will therefore generate an UPDATE statement, use + and will therefore generate an UPDATE statement, use ``object_session(instance).is_modified(instance, include_collections=False)``. - - Column-based attributes can be modified within this method which will - result in their being updated. However *no* changes to the overall + + Column-based attributes can be modified within this method which will + result in their being updated. However *no* changes to the overall flush plan can be made; this means any collection modification or save() operations which occur within this method will not take effect until the next flush call. - + """ return EXT_CONTINUE @@ -260,12 +257,12 @@ class MapperExtension(object): def before_delete(self, mapper, connection, instance): """Receive an object instance before that instance is DELETEed. - - Note that *no* changes to the overall + + Note that *no* changes to the overall flush plan can be made here; this means any collection modification, - save() or delete() operations which occur within this method will + save() or delete() operations which occur within this method will not take effect until the next flush call. - + """ return EXT_CONTINUE @@ -284,7 +281,7 @@ class MapperProperty(object): def setup(self, querycontext, **kwargs): """Called by Query for the purposes of constructing a SQL statement. - + Each MapperProperty associated with the target mapper processes the statement referenced by the query context, adding columns and/or criterion as appropriate. @@ -293,53 +290,57 @@ class MapperProperty(object): pass def create_row_processor(self, selectcontext, mapper, row): - """return a 3-tuple consiting of two row processing functions and an instance post-processing function. - + """Return a 3-tuple consiting of two row processing functions and an instance post-processing function. + Input arguments are the query.SelectionContext and the *first* - applicable row of a result set obtained within query.Query.instances(), called - only the first time a particular mapper's populate_instance() method is invoked for the - overall result. - - The settings contained within the SelectionContext as well as the columns present - in the row (which will be the same columns present in all rows) are used to determine - the presence and behavior of the returned callables. The callables will then be used to process - all rows and to post-process all instances, respectively. - - callables are of the following form:: - + applicable row of a result set obtained within + query.Query.instances(), called only the first time a particular + mapper's populate_instance() method is invoked for the overall result. + + The settings contained within the SelectionContext as well as the + columns present in the row (which will be the same columns present in + all rows) are used to determine the presence and behavior of the + returned callables. The callables will then be used to process all + rows and to post-process all instances, respectively. + + Callables are of the following form:: + def new_execute(instance, row, **flags): - # process incoming instance and given row. the instance is "new" and - # was just created upon receipt of this row. - # flags is a dictionary containing at least the following attributes: - # isnew - indicates if the instance was newly created as a result of reading this row + # process incoming instance and given row. the instance is + # "new" and was just created upon receipt of this row. + # flags is a dictionary containing at least the following + # attributes: + # isnew - indicates if the instance was newly created as a + # result of reading this row # instancekey - identity key of the instance # optional attribute: - # ispostselect - indicates if this row resulted from a 'post' select of additional tables/columns + # ispostselect - indicates if this row resulted from a + # 'post' select of additional tables/columns def existing_execute(instance, row, **flags): - # process incoming instance and given row. the instance is "existing" and - # was created based on a previous row. - + # process incoming instance and given row. the instance is + # "existing" and was created based on a previous row. + def post_execute(instance, **flags): - # process instance after all result rows have been processed. this - # function should be used to issue additional selections in order to - # eagerly load additional properties. - + # process instance after all result rows have been processed. + # this function should be used to issue additional selections + # in order to eagerly load additional properties. + return (new_execute, existing_execute, post_execute) - - either of the three tuples can be ``None`` in which case no function is called. - + + Either of the three tuples can be ``None`` in which case no function + is called. """ - + raise NotImplementedError() def cascade_iterator(self, type, object, recursive=None, halt_on=None): - """iterate through instances related to the given instance along + """Iterate through instances related to the given instance along a particular 'cascade' path, starting with this MapperProperty. - - see PropertyLoader for the related instance implementation. + + See PropertyLoader for the related instance implementation. """ - + return iter([]) def get_criterion(self, query, key, value): @@ -349,9 +350,9 @@ class MapperProperty(object): is a value to be matched. This is only picked up by ``PropertyLoaders``. - This is called by a ``Query``'s ``join_by`` method to - formulate a set of key/value pairs into a ``WHERE`` criterion - that spans multiple tables if needed. + This is called by a ``Query``'s ``join_by`` method to formulate a set + of key/value pairs into a ``WHERE`` criterion that spans multiple + tables if needed. """ return None @@ -370,10 +371,10 @@ class MapperProperty(object): def do_init(self): """Perform subclass-specific initialization steps. - - This is a *template* method called by the + + This is a *template* method called by the ``MapperProperty`` object's init() method.""" - + pass def register_dependencies(self, *args, **kwargs): @@ -408,7 +409,7 @@ class MapperProperty(object): this ``MapperProperty`` to the given value, which may be a column value or an instance. 'operator' is an operator from the operators module, or from sql.Comparator. - + By default uses the PropComparator attached to this MapperProperty under the attribute name "comparator". """ @@ -417,56 +418,57 @@ class MapperProperty(object): class PropComparator(expression.ColumnOperators): """defines comparison operations for MapperProperty objects""" - + def expression_element(self): return self.clause_element() - + def contains_op(a, b): return a.contains(b) contains_op = staticmethod(contains_op) - + def any_op(a, b, **kwargs): return a.any(b, **kwargs) any_op = staticmethod(any_op) - + def has_op(a, b, **kwargs): return a.has(b, **kwargs) has_op = staticmethod(has_op) - + def __init__(self, prop): self.prop = prop def contains(self, other): - """return true if this collection contains other""" + """Return true if this collection contains other""" return self.operate(PropComparator.contains_op, other) def any(self, criterion=None, **kwargs): - """return true if this collection contains any member that meets the given criterion. - - criterion - an optional ClauseElement formulated against the member class' table or attributes. - - \**kwargs - key/value pairs corresponding to member class attribute names which will be compared - via equality to the corresponding values. + """Return true if this collection contains any member that meets the given criterion. + + criterion + an optional ClauseElement formulated against the member class' table + or attributes. + + \**kwargs + key/value pairs corresponding to member class attribute names which + will be compared via equality to the corresponding values. """ return self.operate(PropComparator.any_op, criterion, **kwargs) - + def has(self, criterion=None, **kwargs): - """return true if this element references a member which meets the given criterion. - - + """Return true if this element references a member which meets the given criterion. + criterion - an optional ClauseElement formulated against the member class' table or attributes. - + an optional ClauseElement formulated against the member class' table + or attributes. + \**kwargs - key/value pairs corresponding to member class attribute names which will be compared - via equality to the corresponding values. + key/value pairs corresponding to member class attribute names which + will be compared via equality to the corresponding values. """ return self.operate(PropComparator.has_op, criterion, **kwargs) - + class StrategizedProperty(MapperProperty): """A MapperProperty which uses selectable strategies to affect loading behavior. @@ -518,7 +520,7 @@ def serialize_path(path): (mapper.class_, mapper.entity_name, key) for mapper, key in [(path[i], path[i+1]) for i in range(0, len(path)-1, 2)] ] - + def deserialize_path(path): if path is None: return None @@ -536,18 +538,18 @@ class MapperOption(object): def process_query(self, query): pass - + def process_query_conditionally(self, query): """same as process_query(), except that this option may not apply - to the given query. - - Used when secondary loaders resend existing options to a new + to the given query. + + Used when secondary loaders resend existing options to a new Query.""" self.process_query(query) class ExtensionOption(MapperOption): """a MapperOption that applies a MapperExtension to a query operation.""" - + def __init__(self, ext): self.ext = ext @@ -564,13 +566,13 @@ class PropertyOption(MapperOption): def __init__(self, key, mapper=None): self.key = key self.mapper = mapper - + def process_query(self, query): self._process(query, True) - + def process_query_conditionally(self, query): self._process(query, False) - + def _process(self, query, raiseerr): if self._should_log_debug: self.logger.debug("applying option to Query, property key '%s'" % self.key) @@ -585,7 +587,7 @@ class PropertyOption(MapperOption): path = None l = [] current_path = list(query._current_path) - + if self.mapper: global class_mapper if class_mapper is None: @@ -634,7 +636,7 @@ class StrategizedOption(PropertyOption): def is_chained(self): return False - + def process_query_property(self, query, paths): if self.is_chained(): for path in paths: @@ -664,10 +666,10 @@ class LoaderStrategy(object): list of selected columns, *eager loading* properties may add ``LEFT OUTER JOIN`` clauses to the statement. - * it processes the ``SelectionContext`` at row-processing time. This + * it processes the ``SelectionContext`` at row-processing time. This includes straight population of attributes corresponding to rows, setting instance-level lazyloader callables on newly - constructed instances, and appending child items to scalar/collection + constructed instances, and appending child items to scalar/collection attributes in response to eagerly-loaded relations. """ @@ -678,7 +680,7 @@ class LoaderStrategy(object): def init(self): self.parent = self.parent_property.parent self.key = self.parent_property.key - + def init_class_attribute(self): pass @@ -686,12 +688,11 @@ class LoaderStrategy(object): pass def create_row_processor(self, selectcontext, mapper, row): - """return row processing functions which fulfill the contract specified + """Return row processing functions which fulfill the contract specified by MapperProperty.create_row_processor. - - - StrategizedProperty delegates its create_row_processor method - directly to this method. + + StrategizedProperty delegates its create_row_processor method directly + to this method. """ raise NotImplementedError() diff --git a/lib/sqlalchemy/orm/mapper.py b/lib/sqlalchemy/orm/mapper.py index b99e736b3e..d78973e942 100644 --- a/lib/sqlalchemy/orm/mapper.py +++ b/lib/sqlalchemy/orm/mapper.py @@ -8,7 +8,7 @@ unit which associates a class with a database table. This is a semi-private module; the main configurational API of the ORM is -avaiable in [sqlalchemy.orm#]. +available in [sqlalchemy.orm#]. """ import weakref @@ -119,7 +119,7 @@ class Mapper(object): self._row_translators = {} self._dependency_processors = [] self._clause_adapter = None - + # our 'polymorphic identity', a string name that when located in a result set row # indicates this Mapper should be used to construct the object instance for that row. self.polymorphic_identity = polymorphic_identity @@ -369,11 +369,11 @@ class Mapper(object): if self.version_id_col is None: self.version_id_col = self.inherits.version_id_col - + for mapper in self.iterate_to_root(): if hasattr(mapper, '_genned_equivalent_columns'): del mapper._genned_equivalent_columns - + if self.order_by is False: self.order_by = self.inherits.order_by self.polymorphic_map = self.inherits.polymorphic_map @@ -454,7 +454,7 @@ class Mapper(object): if len(primary_key) == 0: raise exceptions.ArgumentError("Mapper %s could not assemble any primary key columns for mapped table '%s'" % (self, self.mapped_table.description)) - + self.primary_key = primary_key self.__log("Identified primary key columns: " + str(primary_key)) @@ -541,7 +541,7 @@ class Mapper(object): self._genned_equivalent_columns = self.__get_equivalent_columns() return self._genned_equivalent_columns _equivalent_columns = property(_equivalent_columns) - + class _CompileOnAttr(PropComparator): """placeholder class attribute which fires mapper compilation on access""" @@ -705,19 +705,19 @@ class Mapper(object): self.__surrogate_mapper = Mapper(self.class_, self.select_table, non_primary=True, _polymorphic_map=self.polymorphic_map, polymorphic_on=_corresponding_column_or_error(self.select_table, self.polymorphic_on), primary_key=self.primary_key_argument) adapter = sqlutil.ClauseAdapter(self.select_table, equivalents=self.__surrogate_mapper._equivalent_columns) - + if self.order_by: order_by = [expression._literal_as_text(o) for o in util.to_list(self.order_by) or []] order_by = adapter.copy_and_process(order_by) self.__surrogate_mapper.order_by=order_by - + if self._init_properties is not None: for key, prop in self._init_properties.iteritems(): if expression.is_column(prop): self.__surrogate_mapper.add_property(key, _corresponding_column_or_error(self.select_table, prop)) elif (isinstance(prop, list) and expression.is_column(prop[0])): self.__surrogate_mapper.add_property(key, [_corresponding_column_or_error(self.select_table, c) for c in prop]) - + self.__surrogate_mapper._clause_adapter = adapter def _compile_class(self): @@ -804,7 +804,7 @@ class Mapper(object): self.add_property(key, value) def add_property(self, key, prop): - """Add an indiviual MapperProperty to this mapper. + """Add an individual MapperProperty to this mapper. If the mapper has not been compiled yet, just adds the property to the initial properties dictionary sent to the @@ -1301,8 +1301,8 @@ class Mapper(object): try: identitykey = refresh_instance.dict['_instance_key'] except KeyError: - # super-rare condition; a refresh is being called - # on a non-instance-key instance; this is meant to only + # super-rare condition; a refresh is being called + # on a non-instance-key instance; this is meant to only # occur wihtin a flush() identitykey = self._identity_key_from_state(refresh_instance) else: @@ -1556,7 +1556,7 @@ def _load_scalar_attributes(instance, attribute_names): session = mapper.get_session() except exceptions.InvalidRequestError: raise exceptions.UnboundExecutionError("Instance %s is not bound to a Session, and no contextual session is established; attribute refresh operation cannot proceed" % (instance.__class__)) - + state = instance._state if '_instance_key' in state.dict: identity_key = state.dict['_instance_key'] diff --git a/lib/sqlalchemy/orm/query.py b/lib/sqlalchemy/orm/query.py index bcf0f3dd33..ccf6531225 100644 --- a/lib/sqlalchemy/orm/query.py +++ b/lib/sqlalchemy/orm/query.py @@ -69,9 +69,9 @@ class Query(object): self._current_path = () self._only_load_props = None self._refresh_instance = None - + self._adapter = self.select_mapper._clause_adapter - + def _no_criterion(self, meth): q = self._clone() @@ -186,7 +186,7 @@ class Query(object): instance. \**kwargs - all extra keyword arguments are propigated to the constructor of + all extra keyword arguments are propagated to the constructor of Query. """ @@ -253,7 +253,7 @@ class Query(object): Query, and subsequent elements matching columns or entities which were specified via add_column or add_entity. - When adding entities to the result, its generally desireable to add + When adding entities to the result, its generally desirable to add limiting criterion to the query which can associate the primary entity of this Query along with the additional entities. The Query selects from all tables with no joining criterion by default. @@ -287,7 +287,7 @@ class Query(object): class for this Query, and subsequent elements matching columns or entities which were specified via add_column or add_entity. - When adding columns to the result, its generally desireable to add + When adding columns to the result, its generally desirable to add limiting criterion to the query which can associate the primary entity of this Query along with the additional columns, if the column is based on a table or selectable that is not the primary mapped @@ -360,7 +360,7 @@ class Query(object): q._params = q._params.copy() q._params.update(kwargs) return q - + def filter(self, criterion): """apply the given filtering criterion to the query and return the newly resulting ``Query`` @@ -375,7 +375,7 @@ class Query(object): if self._adapter is not None: criterion = self._adapter.traverse(criterion) - + q = self._no_statement("filter") if q._criterion is not None: q._criterion = q._criterion & criterion @@ -412,7 +412,7 @@ class Query(object): currenttables = self._get_joinable_tables() # determine if generated joins need to be aliased on the left - # hand side. + # hand side. if self._adapter and not self._aliases: # at the beginning of a join, look at leftmost adapter adapt_against = self._adapter.selectable elif start.select_table is not start.mapped_table: # in the middle of a join, look for a polymorphic mapper @@ -439,7 +439,7 @@ class Query(object): raise exceptions.InvalidRequestError("Selectable '%s' is not derived from '%s'" % (use_selectable.description, prop.mapper.mapped_table.description)) if not isinstance(use_selectable, expression.Alias): use_selectable = use_selectable.alias() - + if prop._is_self_referential() and not create_aliases and not use_selectable: raise exceptions.InvalidRequestError("Self-referential query on '%s' property requires create_aliases=True argument." % str(prop)) @@ -469,7 +469,7 @@ class Query(object): else: if use_selectable: alias = mapperutil.PropertyAliasedClauses(prop, - prop.primary_join_against(mapper, adapt_against), + prop.primary_join_against(mapper, adapt_against), None, alias, alias=use_selectable @@ -478,7 +478,7 @@ class Query(object): clause = clause.join(alias.alias, crit, isouter=outerjoin) elif create_aliases: alias = mapperutil.PropertyAliasedClauses(prop, - prop.primary_join_against(mapper, adapt_against), + prop.primary_join_against(mapper, adapt_against), None, alias ) @@ -598,7 +598,7 @@ class Query(object): return q def having(self, criterion): - """apply a HAVING criterion to the quer and return the newly resulting ``Query``.""" + """apply a HAVING criterion to the query and return the newly resulting ``Query``.""" if isinstance(criterion, basestring): criterion = sql.text(criterion) @@ -626,9 +626,9 @@ class Query(object): * a 2-tuple containing one of the above, combined with a selectable which derives from the properties' mapped table * a list (not a tuple) containing a combination of any of the above. - + e.g.:: - + session.query(Company).join('employees') session.query(Company).join(['employees', 'tasks']) session.query(Houses).join([Colonials.rooms, Room.closets]) @@ -647,14 +647,14 @@ class Query(object): * a 2-tuple containing one of the above, combined with a selectable which derives from the properties' mapped table * a list (not a tuple) containing a combination of any of the above. - + e.g.:: - + session.query(Company).outerjoin('employees') session.query(Company).outerjoin(['employees', 'tasks']) session.query(Houses).outerjoin([Colonials.rooms, Room.closets]) session.query(Company).join([('employees', people.join(engineers)), Engineer.computers]) - + """ return self._join(prop, id=id, outerjoin=True, aliased=aliased, from_joinpoint=from_joinpoint) @@ -665,7 +665,7 @@ class Query(object): q._from_obj = clause q._joinpoint = mapper q._aliases = aliases - + if aliases: q._adapter = sql_util.ClauseAdapter(aliases.alias).copy_and_chain(q._adapter) else: @@ -1040,7 +1040,7 @@ class Query(object): adapter = None adapter = self._adapter - + # TODO: mappers added via add_entity(), adapt their queries also, # if those mappers are polymorphic @@ -1143,7 +1143,7 @@ class Query(object): context.primary_columns.append(c) statement = sql.select(context.primary_columns + context.secondary_columns, whereclause, from_obj=from_obj, use_labels=True, for_update=for_update, order_by=util.to_list(order_by), **self._select_args()) - + if context.eager_joins: if adapter: context.eager_joins = adapter.traverse(context.eager_joins) @@ -1177,7 +1177,7 @@ class Query(object): return self._alias_ids[alias_id] except KeyError: raise exceptions.InvalidRequestError("Query has no alias identified by '%s'" % alias_id) - + if isinstance(m, type): m = mapper.class_mapper(m) if isinstance(m, mapper.Mapper): -- 2.47.3