[Sqlalchemy-commits] [1482] sqlalchemy/branches/schema/test: activemapper migrated to 0.2, unit test
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-05-21 21:18:15
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head><style type="text/css"><!-- #msg dl { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; } #msg dt { float: left; width: 6em; font-weight: bold; } #msg dt:after { content:':';} #msg dl, #msg dt, #msg ul, #msg li { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; } #msg dl a { font-weight: bold} #msg dl a:link { color:#fc3; } #msg dl a:active { color:#ff0; } #msg dl a:visited { color:#cc6; } h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; } #msg pre { overflow: auto; background: #ffc; border: 1px #fc0 solid; padding: 6px; } #msg ul, pre { overflow: auto; } #patch { width: 100%; } #patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;} #patch .propset h4, #patch .binary h4 {margin:0;} #patch pre {padding:0;line-height:1.2em;margin:0;} #patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;} #patch .propset .diff, #patch .binary .diff {padding:10px 0;} #patch span {display:block;padding:0 10px;} #patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;} #patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;} #patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;} #patch .lines, .info {color:#888;background:#fff;} --></style> <title>[1482] sqlalchemy/branches/schema/test: activemapper migrated to 0.2, unit test cleaned up, all unit tests working for postgres/sqlite/mysql,</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1482</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-21 16:17:58 -0500 (Sun, 21 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>activemapper migrated to 0.2, unit test cleaned up, all unit tests working for postgres/sqlite/mysql, broke out "assignmapper" into its own mod, some games with mapper extensions piling up, factoring change to HistoryArraySet so that update operations that hit backref extensions in the attribute package dont collide with the HAS in an invalid state, various other fixes</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt">sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyattributespy">sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyextactivemapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemymodsthreadlocalpy">sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormsessionpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormtopologicalpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/topological.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyutilpy">sqlalchemy/branches/schema/lib/sqlalchemy/util.py</a></li> <li><a href="#sqlalchemybranchesschematestactivemapperpy">sqlalchemy/branches/schema/test/activemapper.py</a></li> <li><a href="#sqlalchemybranchesschematestalltestspy">sqlalchemy/branches/schema/test/alltests.py</a></li> <li><a href="#sqlalchemybranchesschematestcyclespy">sqlalchemy/branches/schema/test/cycles.py</a></li> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> <li><a href="#sqlalchemybranchesschematestobjectstorepy">sqlalchemy/branches/schema/test/objectstore.py</a></li> <li><a href="#sqlalchemybranchesschematesttestbasepy">sqlalchemy/branches/schema/test/testbase.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyextassignmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/ext/assignmapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemadocbuildcontentsqlconstructiontxt"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/doc/build/content/sqlconstruction.txt 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -9,11 +9,11 @@ </span><span class="cx"> </span><span class="cx"> The examples below all include a dump of the generated SQL corresponding to the query object, as well as a dump of the statement's bind parameters. In all cases, bind parameters are shown as named parameters using the colon format (i.e. ':name'). When the statement is compiled into a database-specific version, the named-parameter statement and its bind values are converted to the proper paramstyle for that database automatically. </span><span class="cx"> </span><del>-For this section, we will mostly use the implcit style of execution, meaning the `Table` objects are associated with an instance of `BoundMetaData`, and constructed `ClauseElement` objects support self-execution. We will also assume the following configuration: </del><ins>+For this section, we will mostly use the implcit style of execution, meaning the `Table` objects are associated with an instance of `BoundMetaData`, and constructed `ClauseElement` objects support self-execution. Assume the following configuration: </ins><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> from sqlalchemy import * </span><del>- metadata = BoundMetaData('sqlite://filename=mydb', strategy='threadlocal', echo=True) </del><ins>+ metadata = BoundMetaData('sqlite:///mydb.db', strategy='threadlocal', echo=True) </ins><span class="cx"> </span><span class="cx"> # a table to store users </span><span class="cx"> users = Table('users', metadata, </span><span class="lines">@@ -87,13 +87,13 @@ </span><span class="cx"> </span><span class="cx"> {python} </span><span class="cx"> # select a literal </span><del>- select(["current_time"], engine=myengine).execute() - {sql}SELECT current_time </del><ins>+ {sql}select(["current_time"], engine=myengine).execute() + SELECT current_time </ins><span class="cx"> {} </span><del>- </del><ins>+ </ins><span class="cx"> # select a function </span><del>- select([func.now()], engine=db).execute() - {sql}SELECT now() </del><ins>+ {sql}select([func.now()], engine=db).execute() + SELECT now() </ins><span class="cx"> {} </span><span class="cx"> </span><span class="cx"> #### Getting Results {@name=resultproxy} </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -208,24 +208,18 @@ </span><span class="cx"> self.set_data(value) </span><span class="cx"> def delattr(self, value, **kwargs): </span><span class="cx"> pass </span><del>- def _setrecord(self, item): - res = util.HistoryArraySet._setrecord(self, item) - if res: - if self.trackparent: - self.sethasparent(item, True) - self.value_changed(self.obj, self.key, item, self, False) - if self.extension is not None: - self.extension.append(self.obj, item) - return res - def _delrecord(self, item): - res = util.HistoryArraySet._delrecord(self, item) - if res: - if self.trackparent: - self.sethasparent(item, False) - self.value_changed(self.obj, self.key, item, self, True) - if self.extension is not None: - self.extension.delete(self.obj, item) - return res </del><ins>+ def do_value_appended(self, item): + if self.trackparent: + self.sethasparent(item, True) + self.value_changed(self.obj, self.key, item, self, False) + if self.extension is not None: + self.extension.append(self.obj, item) + def do_value_deleted(self, item): + if self.trackparent: + self.sethasparent(item, False) + self.value_changed(self.obj, self.key, item, self, True) + if self.extension is not None: + self.extension.delete(self.obj, item) </ins><span class="cx"> </span><span class="cx"> class TriggeredAttribute(ManagedAttribute): </span><span class="cx"> """Used by AttributeManager to allow the attaching of a callable item, representing the future value </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyextactivemapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -1,18 +1,31 @@ </span><del>-from sqlalchemy import objectstore, create_engine, assign_mapper, relation, mapper, join </del><ins>+from sqlalchemy import create_session, relation, mapper, join, DynamicMetaData, class_mapper </ins><span class="cx"> from sqlalchemy import and_, or_ </span><span class="cx"> from sqlalchemy import Table, Column, ForeignKey </span><del>-from sqlalchemy.ext.proxy import ProxyEngine </del><ins>+from sqlalchemy.ext.sessioncontext import SessionContext +from sqlalchemy.ext.assignmapper import assign_mapper +from sqlalchemy import backref as create_backref </ins><span class="cx"> </span><span class="cx"> import inspect </span><span class="cx"> import sys </span><ins>+import sets </ins><span class="cx"> </span><span class="cx"> # </span><span class="cx"> # the "proxy" to the database engine... this can be swapped out at runtime </span><span class="cx"> # </span><del>-engine = ProxyEngine() </del><ins>+metadata = DynamicMetaData("activemapper") </ins><span class="cx"> </span><ins>+# +# thread local SessionContext +# +class Objectstore(SessionContext): + def __getattr__(self, key): + return getattr(self.current, key) + def get_session(self): + return self.current </ins><span class="cx"> </span><ins>+objectstore = Objectstore(create_session) </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> # </span><span class="cx"> # declarative column declaration - this is so that we can infer the colname </span><span class="cx"> # </span><span class="lines">@@ -49,7 +62,7 @@ </span><span class="cx"> </span><span class="cx"> class one_to_one(relationship): </span><span class="cx"> def __init__(self, classname, colname=None, backref=None, private=False, lazy=True): </span><del>- relationship.__init__(self, classname, colname, backref, private, lazy, uselist=False) </del><ins>+ relationship.__init__(self, classname, colname, create_backref(backref, uselist=False), private, lazy, uselist=False) </ins><span class="cx"> </span><span class="cx"> class many_to_many(relationship): </span><span class="cx"> def __init__(self, classname, secondary, backref=None, lazy=True): </span><span class="lines">@@ -82,8 +95,9 @@ </span><span class="cx"> private=reldesc.private, </span><span class="cx"> lazy=reldesc.lazy, </span><span class="cx"> uselist=reldesc.uselist) </span><del>- assign_mapper(klass, klass.table, properties=relations, - inherits=getattr(klass, "_base_mapper", None)) </del><ins>+ class_mapper(klass).add_properties(relations) + #assign_mapper(objectstore, klass, klass.table, properties=relations, + # inherits=getattr(klass, "_base_mapper", None)) </ins><span class="cx"> if was_deferred: __deferred_classes__.remove(klass) </span><span class="cx"> </span><span class="cx"> if not was_deferred: </span><span class="lines">@@ -94,12 +108,12 @@ </span><span class="cx"> </span><span class="cx"> class ActiveMapperMeta(type): </span><span class="cx"> classes = {} </span><del>- </del><ins>+ metadatas = sets.Set() </ins><span class="cx"> def __init__(cls, clsname, bases, dict): </span><span class="cx"> table_name = clsname.lower() </span><span class="cx"> columns = [] </span><span class="cx"> relations = {} </span><del>- _engine = getattr( sys.modules[cls.__module__], "__engine__", engine ) </del><ins>+ _metadata = getattr( sys.modules[cls.__module__], "__metadata__", metadata ) </ins><span class="cx"> </span><span class="cx"> if 'mapping' in dict: </span><span class="cx"> members = inspect.getmembers(dict.get('mapping')) </span><span class="lines">@@ -108,8 +122,8 @@ </span><span class="cx"> table_name = value </span><span class="cx"> continue </span><span class="cx"> </span><del>- if '__engine__' == name: - _engine= value </del><ins>+ if '__metadata__' == name: + _metadata= value </ins><span class="cx"> continue </span><span class="cx"> </span><span class="cx"> if name.startswith('__'): continue </span><span class="lines">@@ -131,14 +145,15 @@ </span><span class="cx"> </span><span class="cx"> if isinstance(value, relationship): </span><span class="cx"> relations[name] = value </span><del>- assert _engine is not None, "No engine specified" - cls.table = Table(table_name, _engine, *columns) </del><ins>+ assert _metadata is not None, "No MetaData specified" + ActiveMapperMeta.metadatas.add(_metadata) + cls.table = Table(table_name, _metadata, *columns) </ins><span class="cx"> # check for inheritence </span><span class="cx"> if hasattr( bases[0], "mapping" ): </span><span class="cx"> cls._base_mapper= bases[0].mapper </span><del>- assign_mapper(cls, cls.table, inherits=cls._base_mapper) </del><ins>+ assign_mapper(objectstore, cls, cls.table, inherits=cls._base_mapper) </ins><span class="cx"> else: </span><del>- assign_mapper(cls, cls.table) </del><ins>+ assign_mapper(objectstore, cls, cls.table) </ins><span class="cx"> cls.relations = relations </span><span class="cx"> ActiveMapperMeta.classes[clsname] = cls </span><span class="cx"> </span><span class="lines">@@ -160,6 +175,6 @@ </span><span class="cx"> # </span><span class="cx"> </span><span class="cx"> def create_tables(): </span><del>- for klass in ActiveMapperMeta.classes.values(): - klass.table.create() </del><ins>+ for metadata in ActiveMapperMeta.metadatas: + metadata.create_all() </ins><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyextassignmapperpy"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/lib/sqlalchemy/ext/assignmapper.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ext/assignmapper.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ext/assignmapper.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -0,0 +1,34 @@ </span><ins>+from sqlalchemy import mapper, util +import types + +def monkeypatch_query_method(ctx, class_, name): + def do(self, *args, **kwargs): + query = class_.mapper.query(session=ctx.current) + return getattr(query, name)(*args, **kwargs) + setattr(class_, name, classmethod(do)) + +def monkeypatch_objectstore_method(ctx, class_, name): + def do(self, *args, **kwargs): + session = ctx.current + return getattr(session, name)(self, *args, **kwargs) + setattr(class_, name, do) + +def assign_mapper(ctx, class_, *args, **kwargs): + kwargs.setdefault("is_primary", True) + if not isinstance(getattr(class_, '__init__'), types.MethodType): + def __init__(self, **kwargs): + for key, value in kwargs.items(): + setattr(self, key, value) + class_.__init__ = __init__ + extension = kwargs.pop('extension', None) + if extension is not None: + extension = util.to_list(extension) + extension.append(ctx.mapper_extension) + else: + extension = ctx.mapper_extension + m = mapper(class_, extension=extension, *args, **kwargs) + class_.mapper = m + for name in ['get', 'select', 'select_by', 'selectone', 'get_by', 'join_to', 'join_via']: + monkeypatch_query_method(ctx, class_, name) + for name in ['flush', 'delete', 'expire', 'refresh', 'expunge', 'merge', 'update', 'save_or_update']: + monkeypatch_objectstore_method(ctx, class_, name) </ins></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemymodsthreadlocalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -1,5 +1,6 @@ </span><span class="cx"> from sqlalchemy import util, engine, mapper </span><span class="cx"> from sqlalchemy.ext.sessioncontext import SessionContext </span><ins>+import sqlalchemy.ext.assignmapper as assignmapper </ins><span class="cx"> from sqlalchemy.orm.mapper import global_extensions </span><span class="cx"> from sqlalchemy.orm.session import Session </span><span class="cx"> import sqlalchemy </span><span class="lines">@@ -25,34 +26,11 @@ </span><span class="cx"> def get_session(self): </span><span class="cx"> return self.current </span><span class="cx"> </span><del>-def monkeypatch_query_method(class_, name): - def do(self, *args, **kwargs): - query = class_.mapper.query() - getattr(query, name)(*args, **kwargs) - setattr(class_, name, classmethod(do)) - -def monkeypatch_objectstore_method(class_, name): - def do(self, *args, **kwargs): - session = sqlalchemy.objectstore.current - getattr(session, name)(self, *args, **kwargs) - setattr(class_, name, do) - </del><span class="cx"> def assign_mapper(class_, *args, **kwargs): </span><del>- kwargs.setdefault("is_primary", True) - if not isinstance(getattr(class_, '__init__'), types.MethodType): - def __init__(self, **kwargs): - for key, value in kwargs.items(): - setattr(self, key, value) - class_.__init__ = __init__ - m = mapper(class_, *args, **kwargs) - class_.mapper = m - for name in ['get', 'select', 'select_by', 'selectone', 'get_by']: - monkeypatch_query_method(class_, name) - for name in ['flush', 'delete', 'expire', 'refresh', 'expunge', 'merge', 'update', 'save_or_update']: - monkeypatch_objectstore_method(class_, name) </del><ins>+ assignmapper.assign_mapper(objectstore, class_, *args, **kwargs) </ins><span class="cx"> </span><span class="cx"> def _mapper_extension(): </span><del>- return SessionContext._get_mapper_extension(sqlalchemy.objectstore) </del><ins>+ return SessionContext._get_mapper_extension(objectstore) </ins><span class="cx"> </span><span class="cx"> objectstore = Objectstore(Session) </span><span class="cx"> def install_plugin(): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -53,20 +53,31 @@ </span><span class="cx"> concrete=False, </span><span class="cx"> select_table=None): </span><span class="cx"> </span><del>- ext = MapperExtension() - </del><ins>+ # uber-pendantic style of making mapper chain, as various testbase/ + # threadlocal/assignmapper combinations keep putting dupes etc. in the list + # TODO: do something that isnt 21 lines.... + extlist = util.HashSet() </ins><span class="cx"> for ext_class in global_extensions: </span><span class="cx"> if isinstance(ext_class, MapperExtension): </span><del>- ext = ext_class.chain(ext) </del><ins>+ extlist.append(ext_class) </ins><span class="cx"> else: </span><del>- ext = ext_class().chain(ext) </del><ins>+ extlist.append(ext_class()) </ins><span class="cx"> </span><span class="cx"> if extension is not None: </span><span class="cx"> for ext_obj in util.to_list(extension): </span><del>- ext = ext_obj.chain(ext) </del><ins>+ extlist.append(ext_obj) + + self.extension = None + previous = None + for ext in extlist: + if self.extension is None: + self.extension = ext + if previous is not None: + previous.chain(ext) + previous = ext + if self.extension is None: + self.extension = MapperExtension() </ins><span class="cx"> </span><del>- self.extension = ext - </del><span class="cx"> self.class_ = class_ </span><span class="cx"> self.entity_name = entity_name </span><span class="cx"> self.class_key = ClassKey(class_, entity_name) </span><span class="lines">@@ -954,8 +965,10 @@ </span><span class="cx"> def __init__(self): </span><span class="cx"> self.next = None </span><span class="cx"> def chain(self, ext): </span><ins>+ if ext is self: + raise "nu uh " + repr(self) + " " + repr(ext) </ins><span class="cx"> self.next = ext </span><del>- return self </del><ins>+ return self </ins><span class="cx"> def get_session(self): </span><span class="cx"> """called to retrieve a contextual Session instance with which to </span><span class="cx"> register a new object. Note: this is not called if a session is </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -60,7 +60,7 @@ </span><span class="cx"> for t in self.connections.values(): </span><span class="cx"> t[0].close() </span><span class="cx"> self.session.transaction = None </span><del>- </del><ins>+ </ins><span class="cx"> class Session(object): </span><span class="cx"> """encapsulates a set of objects being operated upon within an object-relational operation.""" </span><span class="cx"> def __init__(self, bind_to=None, hash_key=None, import_session=None, echo_uow=False): </span><span class="lines">@@ -366,7 +366,7 @@ </span><span class="cx"> if getattr(obj, '_sa_session_id', None) != self.hash_key: </span><span class="cx"> old = getattr(obj, '_sa_session_id', None) </span><span class="cx"> if old is not None: </span><del>- raise exceptions.InvalidRequestError("Object '%s' is already attached to session '%s'" % (repr(obj), old)) </del><ins>+ raise exceptions.InvalidRequestError("Object '%s' is already attached to session '%s' (this is '%s')" % (repr(obj), old, id(self))) </ins><span class="cx"> </span><span class="cx"> # auto-removal from the old session is disabled. but if we decide to </span><span class="cx"> # turn it back on, do it as below: gingerly since _sessions is a WeakValueDict </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormtopologicalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/topological.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/topological.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/topological.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -102,7 +102,7 @@ </span><span class="cx"> n.cycles = Set([n]) </span><span class="cx"> continue </span><span class="cx"> else: </span><del>- raise CommitError("Self-referential dependency detected " + repr(t)) </del><ins>+ raise FlushError("Self-referential dependency detected " + repr(t)) </ins><span class="cx"> childnode = nodes[t[1]] </span><span class="cx"> parentnode = nodes[t[0]] </span><span class="cx"> self._add_edge(edges, (parentnode, childnode)) </span><span class="lines">@@ -136,7 +136,7 @@ </span><span class="cx"> continue </span><span class="cx"> else: </span><span class="cx"> # long cycles not allowed </span><del>- raise CommitError("Circular dependency detected " + repr(edges) + repr(queue)) </del><ins>+ raise FlushError("Circular dependency detected " + repr(edges) + repr(queue)) </ins><span class="cx"> node = queue.pop() </span><span class="cx"> if not hasattr(node, '_cyclical'): </span><span class="cx"> output.append(node) </span><span class="lines">@@ -328,7 +328,7 @@ </span><span class="cx"> elif parentnode.is_descendant_of(childnode): </span><span class="cx"> # check for a line thats backwards with nodes in between, this is a </span><span class="cx"> # circular dependency (although confirmation on this would be helpful) </span><del>- raise CommitError("Circular dependency detected") </del><ins>+ raise FlushError("Circular dependency detected") </ins><span class="cx"> elif not childnode.is_descendant_of(parentnode): </span><span class="cx"> # if relationship doesnt exist, connect nodes together </span><span class="cx"> root = childnode.get_sibling_ancestor(parentnode) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -695,7 +695,7 @@ </span><span class="cx"> self.__engines[engine_or_url] = engine_or_url </span><span class="cx"> self.context._engine = engine_or_url </span><span class="cx"> def is_bound(self): </span><del>- return s.context._engine is not None </del><ins>+ return self.context._engine is not None </ins><span class="cx"> def dispose(self): </span><span class="cx"> """disposes all Engines to which this DynamicMetaData has been connected.""" </span><span class="cx"> for e in self.__engines.values(): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/util.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/util.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/lib/sqlalchemy/util.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -257,44 +257,55 @@ </span><span class="cx"> # first mark everything current as "deleted" </span><span class="cx"> for i in self.data: </span><span class="cx"> self.records[i] = False </span><ins>+ self.do_value_deleted(value) </ins><span class="cx"> </span><span class="cx"> # switch array </span><span class="cx"> self.data = data </span><span class="cx"> </span><span class="cx"> # TODO: fix this up, remove items from array while iterating </span><span class="cx"> for i in range(0, len(self.data)): </span><del>- if not self._setrecord(self.data[i]): - del self.data[i] - i -= 1 </del><ins>+ if not self.__setrecord(self.data[i], False): + del self.data[i] + i -= 1 + for item in self.data: + self.do_value_appended(item) </ins><span class="cx"> def history_contains(self, obj): </span><span class="cx"> """returns true if the given object exists within the history </span><span class="cx"> for this HistoryArrayList.""" </span><span class="cx"> return self.records.has_key(obj) </span><span class="cx"> def __hash__(self): </span><span class="cx"> return id(self) </span><del>- def _setrecord(self, item): - if self.readonly: - raise InvalidRequestError("This list is read only") </del><ins>+ def do_value_appended(self, value): + pass + def do_value_deleted(self, value): + pass + def __setrecord(self, item, dochanged=True): </ins><span class="cx"> try: </span><span class="cx"> val = self.records[item] </span><span class="cx"> if val is True or val is None: </span><span class="cx"> return False </span><span class="cx"> else: </span><span class="cx"> self.records[item] = None </span><ins>+ if dochanged: + self.do_value_appended(item) </ins><span class="cx"> return True </span><span class="cx"> except KeyError: </span><span class="cx"> self.records[item] = True </span><ins>+ if dochanged: + self.do_value_appended(item) </ins><span class="cx"> return True </span><del>- def _delrecord(self, item): - if self.readonly: - raise InvalidRequestError("This list is read only") </del><ins>+ def __delrecord(self, item, dochanged=True): </ins><span class="cx"> try: </span><span class="cx"> val = self.records[item] </span><span class="cx"> if val is None: </span><span class="cx"> self.records[item] = False </span><ins>+ if dochanged: + self.do_value_deleted(item) </ins><span class="cx"> return True </span><span class="cx"> elif val is True: </span><span class="cx"> del self.records[item] </span><ins>+ if dochanged: + self.do_value_deleted(item) </ins><span class="cx"> return True </span><span class="cx"> return False </span><span class="cx"> except KeyError: </span><span class="lines">@@ -350,10 +361,10 @@ </span><span class="cx"> def has_item(self, item): </span><span class="cx"> return self.records.has_key(item) and self.records[item] is not False </span><span class="cx"> def __setitem__(self, i, item): </span><del>- if self._setrecord(item): </del><ins>+ if self.__setrecord(item): </ins><span class="cx"> self.data[i] = item </span><span class="cx"> def __delitem__(self, i): </span><del>- self._delrecord(self.data[i]) </del><ins>+ self.__delrecord(self.data[i]) </ins><span class="cx"> del self.data[i] </span><span class="cx"> def __setslice__(self, i, j, other): </span><span class="cx"> i = max(i, 0); j = max(j, 0) </span><span class="lines">@@ -363,25 +374,25 @@ </span><span class="cx"> l = other </span><span class="cx"> else: </span><span class="cx"> l = list(other) </span><del>- g = [a for a in l if self._setrecord(a)] </del><ins>+ g = [a for a in l if self.__setrecord(a)] </ins><span class="cx"> self.data[i:] = g </span><span class="cx"> def __delslice__(self, i, j): </span><span class="cx"> i = max(i, 0); j = max(j, 0) </span><span class="cx"> for a in self.data[i:j]: </span><del>- self._delrecord(a) </del><ins>+ self.__delrecord(a) </ins><span class="cx"> del self.data[i:j] </span><span class="cx"> def append(self, item): </span><del>- if self._setrecord(item): </del><ins>+ if self.__setrecord(item): </ins><span class="cx"> self.data.append(item) </span><span class="cx"> def insert(self, i, item): </span><del>- if self._setrecord(item): </del><ins>+ if self.__setrecord(item): </ins><span class="cx"> self.data.insert(i, item) </span><span class="cx"> def pop(self, i=-1): </span><span class="cx"> item = self.data[i] </span><del>- if self._delrecord(item): </del><ins>+ if self.__delrecord(item): </ins><span class="cx"> return self.data.pop(i) </span><span class="cx"> def remove(self, item): </span><del>- if self._delrecord(item): </del><ins>+ if self.__delrecord(item): </ins><span class="cx"> self.data.remove(item) </span><span class="cx"> def extend(self, item_list): </span><span class="cx"> for item in item_list: </span></span></pre></div> <a id="sqlalchemybranchesschematestactivemapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/activemapper.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/activemapper.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/test/activemapper.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -1,80 +1,83 @@ </span><del>-from activemapper import ActiveMapper, column, one_to_many, one_to_one -from sqlalchemy import objectstore -from sqlalchemy import and_, or_ </del><ins>+from sqlalchemy.ext.activemapper import ActiveMapper, column, one_to_many, one_to_one, objectstore +from sqlalchemy import and_, or_, clear_mappers </ins><span class="cx"> from sqlalchemy import ForeignKey, String, Integer, DateTime </span><span class="cx"> from datetime import datetime </span><span class="cx"> </span><span class="cx"> import unittest </span><del>-import activemapper </del><ins>+import sqlalchemy.ext.activemapper as activemapper </ins><span class="cx"> </span><del>-# -# application-level model objects -# </del><ins>+import testbase </ins><span class="cx"> </span><del>-class Person(ActiveMapper): - class mapping: - id = column(Integer, primary_key=True) - full_name = column(String) - first_name = column(String) - middle_name = column(String) - last_name = column(String) - birth_date = column(DateTime) - ssn = column(String) - gender = column(String) - home_phone = column(String) - cell_phone = column(String) - work_phone = column(String) - prefs_id = column(Integer, foreign_key=ForeignKey('preferences.id')) - addresses = one_to_many('Address', colname='person_id', backref='person') - preferences = one_to_one('Preferences', colname='pref_id', backref='person') - - def __str__(self): - s = '%s\n' % self.full_name - s += ' * birthdate: %s\n' % (self.birth_date or 'not provided') - s += ' * fave color: %s\n' % (self.preferences.favorite_color or 'Unknown') - s += ' * personality: %s\n' % (self.preferences.personality_type or 'Unknown') </del><ins>+class testcase(testbase.PersistTest): + def setUpAll(self): + global Person, Preferences, Address </ins><span class="cx"> </span><del>- for address in self.addresses: - s += ' * address: %s\n' % address.address_1 - s += ' %s, %s %s\n' % (address.city, address.state, address.postal_code) - - return s </del><ins>+ class Person(ActiveMapper): + class mapping: + id = column(Integer, primary_key=True) + full_name = column(String) + first_name = column(String) + middle_name = column(String) + last_name = column(String) + birth_date = column(DateTime) + ssn = column(String) + gender = column(String) + home_phone = column(String) + cell_phone = column(String) + work_phone = column(String) + prefs_id = column(Integer, foreign_key=ForeignKey('preferences.id')) + addresses = one_to_many('Address', colname='person_id', backref='person') + preferences = one_to_one('Preferences', colname='pref_id', backref='person') </ins><span class="cx"> </span><ins>+ def __str__(self): + s = '%s\n' % self.full_name + s += ' * birthdate: %s\n' % (self.birth_date or 'not provided') + s += ' * fave color: %s\n' % (self.preferences.favorite_color or 'Unknown') + s += ' * personality: %s\n' % (self.preferences.personality_type or 'Unknown') </ins><span class="cx"> </span><del>-class Preferences(ActiveMapper): - class mapping: - __table__ = 'preferences' - id = column(Integer, primary_key=True) - favorite_color = column(String) - personality_type = column(String) </del><ins>+ for address in self.addresses: + s += ' * address: %s\n' % address.address_1 + s += ' %s, %s %s\n' % (address.city, address.state, address.postal_code) </ins><span class="cx"> </span><ins>+ return s </ins><span class="cx"> </span><del>-class Address(ActiveMapper): - class mapping: - id = column(Integer, primary_key=True) - type = column(String) - address_1 = column(String) - city = column(String) - state = column(String) - postal_code = column(String) - person_id = column(Integer, foreign_key=ForeignKey('person.id')) </del><ins>+ class Preferences(ActiveMapper): + class mapping: + __table__ = 'preferences' + id = column(Integer, primary_key=True) + favorite_color = column(String) + personality_type = column(String) </ins><span class="cx"> </span><ins>+ class Address(ActiveMapper): + class mapping: + id = column(Integer, primary_key=True) + type = column(String) + address_1 = column(String) + city = column(String) + state = column(String) + postal_code = column(String) + person_id = column(Integer, foreign_key=ForeignKey('person.id')) </ins><span class="cx"> </span><ins>+ activemapper.metadata.connect(testbase.db) + activemapper.create_tables() </ins><span class="cx"> </span><del>-class testcase(unittest.TestCase): - </del><ins>+ def tearDownAll(self): + clear_mappers() + </ins><span class="cx"> def tearDown(self): </span><del>- people = Person.select() - for person in people: person.delete() </del><ins>+ for t in activemapper.metadata.table_iterator(reverse=True): + t.delete().execute() + #people = Person.select() + #for person in people: person.delete() </ins><span class="cx"> </span><del>- addresses = Address.select() - for address in addresses: address.delete() </del><ins>+ #addresses = Address.select() + #for address in addresses: address.delete() </ins><span class="cx"> </span><del>- preferences = Preferences.select() - for preference in preferences: preference.delete() </del><ins>+ #preferences = Preferences.select() + #for preference in preferences: preference.delete() </ins><span class="cx"> </span><del>- objectstore.commit() - objectstore.clear() </del><ins>+ #objectstore.flush() + #objectstore.clear() </ins><span class="cx"> </span><span class="cx"> def create_person_one(self): </span><span class="cx"> # create a person </span><span class="lines">@@ -131,8 +134,7 @@ </span><span class="cx"> </span><span class="cx"> def test_create(self): </span><span class="cx"> p1 = self.create_person_one() </span><del>- - objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><span class="cx"> results = Person.select() </span><span class="lines">@@ -148,14 +150,14 @@ </span><span class="cx"> def test_delete(self): </span><span class="cx"> p1 = self.create_person_one() </span><span class="cx"> </span><del>- objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><span class="cx"> results = Person.select() </span><span class="cx"> self.assertEquals(len(results), 1) </span><span class="cx"> </span><span class="cx"> results[0].delete() </span><del>- objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><span class="cx"> results = Person.select() </span><span class="lines">@@ -166,7 +168,7 @@ </span><span class="cx"> p1 = self.create_person_one() </span><span class="cx"> p2 = self.create_person_two() </span><span class="cx"> </span><del>- objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><span class="cx"> # select and make sure we get back two results </span><span class="lines">@@ -197,25 +199,31 @@ </span><span class="cx"> # FIXME: I don't know why, but it seems that my backwards relationship </span><span class="cx"> # on preferences still ends up being a list even though I pass </span><span class="cx"> # in uselist=False... </span><ins>+ # FIXED: the backref is a new PropertyLoader which needs its own "uselist". + # uses a function which I dont think existed when you first wrote ActiveMapper. </ins><span class="cx"> p1 = self.create_person_one() </span><span class="cx"> self.assertEquals(p1.preferences.person, p1) </span><span class="cx"> p1.delete() </span><span class="cx"> </span><del>- objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> def test_select_by(self): </span><span class="cx"> # FIXME: either I don't understand select_by, or it doesn't work. </span><ins>+ # FIXED (as good as we can for now): yup....everyone thinks it works that way....it only + # generates joins for keyword arguments, not ColumnClause args. would need a new layer of + # "MapperClause" objects to use properties in expressions. (MB) </ins><span class="cx"> </span><span class="cx"> p1 = self.create_person_one() </span><span class="cx"> p2 = self.create_person_two() </span><span class="cx"> </span><del>- objectstore.commit() </del><ins>+ objectstore.flush() </ins><span class="cx"> objectstore.clear() </span><span class="cx"> </span><del>- results = Person.select_by( - Address.c.postal_code.like('30075') </del><ins>+ results = Person.select( + Address.c.postal_code.like('30075') & + Person.join_to('addresses') </ins><span class="cx"> ) </span><span class="cx"> self.assertEquals(len(results), 1) </span><span class="cx"> </span><span class="lines">@@ -223,8 +231,6 @@ </span><span class="cx"> </span><span class="cx"> if __name__ == '__main__': </span><span class="cx"> # go ahead and setup the database connection, and create the tables </span><del>- activemapper.engine.connect('sqlite:///', echo=False) - activemapper.create_tables() </del><span class="cx"> </span><span class="cx"> # launch the unit tests </span><span class="cx"> unittest.main() </span><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemybranchesschematestalltestspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/alltests.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/alltests.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/test/alltests.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -56,6 +56,7 @@ </span><span class="cx"> </span><span class="cx"> # extensions </span><span class="cx"> 'proxy_engine', </span><ins>+ 'activemapper' </ins><span class="cx"> #'wsgi_test', </span><span class="cx"> </span><span class="cx"> ) </span></span></pre></div> <a id="sqlalchemybranchesschematestcyclespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/cycles.py (1481 => 1482)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/cycles.py 2006-05-21 18:34:12 UTC (rev 1481) +++ sqlalchemy/branches/schema/test/cycles.py 2006-05-21 21:17:58 UTC (rev 1482) </span><span class="lines">@@ -22,26 +22,22 @@ </span><span class="cx"> class SelfReferentialTest(AssertMixin): </span><span class="cx"> """tests a self-referential mapper, with an additional list of child objects.""" </span><span class="cx"> def setUpAll(self): </span><del>- testbase.metadata.tables.clear() - global t1 - global t2 - t1 = Table('t1', testbase.metadata, </del><ins>+ global t1, t2, metadata + metadata = BoundMetaData(testbase.db) + t1 = Table('t1', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('parent_c1', Integer, ForeignKey('t1.c1')), </span><span class="cx"> Column('data', String(20)) </span><span class="cx"> ) </span><del>- t2 = Table('t2', testbase.metadata, </del><ins>+ t2 = Table('t2', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('c1id', Integer, ForeignKey('t1.c1')), </span><span class="cx"> Column('data', String(20)) </span><span class="cx"> ) </span><del>- t1.create() - t2.create() </del><ins>+ metadata.create_all() </ins><span class="cx"> def tearDownAll(self): </span><del>- t2.drop() - t1.drop() </del><ins>+ metadata.drop_all() </ins><span class="cx"> def setUp(self): </span><del>- objectstore.clear() </del><span class="cx"> clear_mappers() </span><span class="cx"> </span><span class="cx"> def testsingle(self): </span><span class="lines">@@ -53,9 +49,11 @@ </span><span class="cx"> }) </span><span class="cx"> a = C1('head c1') </span><span class="cx"> a.c1s.append(C1('another c1')) </span><del>- objectstore.flush() - objectstore.delete(a) - objectstore.flush() </del><ins>+ sess = create_session() + sess.save(a) + sess.flush() + sess.delete(a) + sess.flush() </ins><span class="cx"> </span><span class="cx"> def testcycle(self): </span><span class="cx"> class C1(Tester): </span><span class="lines">@@ -75,36 +73,34 @@ </span><span class="cx"> a.c1s[0].c1s.append(C1('subchild2')) </span><span class="cx"> a.c1s[1].c2s.append(C2('child2 data1')) </span><span class="cx"> a.c1s[1].c2s.append(C2('child2 data2')) </span><del>- objectstore.flush() </del><ins>+ sess = create_session() + sess.save(a) + sess.flush() </ins><span class="cx"> </span><del>- objectstore.delete(a) - objectstore.flush() </del><ins>+ sess.delete(a) + sess.flush() </ins><span class="cx"> </span><span class="cx"> class BiDirectionalOneToManyTest(AssertMixin): </span><span class="cx"> """tests two mappers with a one-to-many relation to each other.""" </span><span class="cx"> def setUpAll(self): </span><del>- testbase.metadata.tables.clear() - global t1 - global t2 - t1 = Table('t1', testbase.metadata, </del><ins>+ global t1, t2, metadata + metadata = BoundMetaData(testbase.db) + t1 = Table('t1', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('c2', Integer, ForeignKey('t2.c1')) </span><span class="cx"> ) </span><del>- t2 = Table('t2', testbase.metadata, </del><ins>+ t2 = Table('t2', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('c2', Integer) </span><span class="cx"> ) </span><del>- t2.create() - t1.create() </del><ins>+ metadata.create_all() </ins><span class="cx"> t2.c.c2.append_item(ForeignKey('t1.c1')) </span><span class="cx"> def tearDownAll(self): </span><del>- t1.drop() </del><ins>+ t1.drop() </ins><span class="cx"> t2.drop() </span><del>- def setUp(self): - objectstore.clear() - #objectstore.LOG = True </del><ins>+ #metadata.drop_all() + def tearDown(self): </ins><span class="cx"> clear_mappers() </span><del>- </del><span class="cx"> def testcycle(self): </span><span class="cx"> class C1(object):pass </span><span class="cx"> class C2(object):pass </span><span class="lines">@@ -123,35 +119,33 @@ </span><span class="cx"> a.c2s.append(b) </span><span class="cx"> d.c1s.append(c) </span><span class="cx"> b.c1s.append(c) </span><del>- objectstore.flush() </del><ins>+ sess = create_session() + [sess.save(x) for x in [a,b,c,d,e,f]] + sess.flush() </ins><span class="cx"> </span><span class="cx"> class BiDirectionalOneToManyTest2(AssertMixin): </span><span class="cx"> """tests two mappers with a one-to-many relation to each other, with a second one-to-many on one of the mappers""" </span><span class="cx"> def setUpAll(self): </span><del>- testbase.metadata.tables.clear() - global t1 - global t2 - global t3 - t1 = Table('t1', testbase.metadata, </del><ins>+ global t1, t2, t3, metadata + metadata = BoundMetaData(testbase.db) + t1 = Table('t1', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('c2', Integer, ForeignKey('t2.c1')), </span><span class="cx"> ) </span><del>- t2 = Table('t2', testbase.metadata, </del><ins>+ t2 = Table('t2', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('c2', Integer), </span><span class="cx"> ) </span><span class="cx"> t2.create() </span><span class="cx"> t1.create() </span><span class="cx"> t2.c.c2.append_item(ForeignKey('t1.c1')) </span><del>- t3 = Table('t1_data', testbase.metadata, </del><ins>+ t3 = Table('t1_data', metadata, </ins><span class="cx"> Column('c1', Integer, primary_key=True), </span><span class="cx"> Column('t1id', Integer, ForeignKey('t1.c1')), </span><span class="cx"> Column('data', String(20))) </span><span class="cx"> t3.create() </span><span class="cx"> </span><del>- def setUp(self): - objectstore.clear() - #objectstore.LOG = True </del><ins>+ def tearDown(self): </ins><span class="cx"> clear_mappers() </span><span class="cx"> </span><span class="cx"> def tearDownAll(self): </span><span class="lines">@@ -185,25 +179,28 @@ </span><span class="cx"> a.data.append(C1Data('c1data1')) </span><span class="cx"> a.data.append(C1Data('c1data2')) </span><span class="cx"> c.data.append(C1Data('c1data3')) </span><del>- objectstore.flush() </del><ins>+ sess = create_session() + [sess.save(x) for x in [a,b,c,d,e,f]] + sess.flush() </ins><span class="cx"> </span><del>- objectstore.delete(d) - objectstore.delete(c) - objectstore.flush() </del><ins>+ sess.delete(d) + sess.delete(c) + sess.flush() </ins><span class="cx"> </span><span class="cx"> class OneToManyManyToOneTest(AssertMixin): </span><span class="cx"> """tests two mappers, one has a one-to-many on the other mapper, the other has a separate many-to-one relationship to the first. </span><span class="cx"> two tests will have a row for each item that is dependent on the other. without the "post_update" flag, such relationships </span><span class="cx"> raise an exception when dependencies are sorted.""" </span><span class="cx"> def setUpAll(self): </span><del>- testbase.metadata.tables.clear() </del><ins>+ global metadata + metadata = BoundMetaData(testbase.db) </ins><span class="cx"> global person </span><span class="cx"> global ball </span><del>- ball = Table('ball', db, </del><ins>+ ball = Table('ball', metadata, </ins><span class="cx"> Column('id', Integer, Sequence('ball_id_seq', optional=True), primary_key=True), </span><span class="cx"> Column('person_id', Integer), </span><span class="cx"> ) </span><del>- person = Table('person', db, </del><ins>+ person = Table('person', metadata, </ins><span class="cx"> Column('id', Integer, Sequence('person_id_seq', optional=True), primary_key=True), </span><span class="cx"> Column('favoriteBall_id', Integer, ForeignKey('ball.id')), </span><span class="cx"> # Column('favoriteBall_id', Integer), </span><span class="lines">@@ -223,9 +220,7 @@ </span><span class="cx"> person.drop() </span><span class="cx"> ball.drop() </span><span class="cx"> </span><del>- def setUp(self): - objectstore.clear() - #objectstore.LOG = True </del><ins>+ def tearDown(self): </ins><span class="cx"> clear_mappers() </span><span class="cx"> </span><span class="cx"> def testcycle(self): </span><span class="lines">@@ -249,7 +244,10 @@ </span><span class="cx"> b = Ball() </span><span class="cx"> p = Person() </span><span class="cx"> p.balls.append(b) </span><del>- objectstore.flush() </del><ins>+ sess = create_session() + sess.save(b) + sess.save(b) + sess.flush() </ins><span class="cx"> </span><span class="cx"> def testpostupdate_m2o(self): </span><span class="cx"> """tests a cycle between two rows, with a post_update on the many-to-one""" </span><span class="lines">@@ -275,8 +273,11 @@ </span><span class="cx"> p.balls.append(Ball()) </span><span class="cx"> p.balls.append(Ball()) </span><span class="cx"> p.favorateBall = b </span><del>- - self.assert_sql(db, lambda: objectstore.get_session().flush(), [ </del><ins>+ sess = create_session() + sess.save(b) + sess.save(p) + + self.assert_sql(db, lambda: sess.flush(), [ </ins><span class="cx"> ( </span><span class="cx"> "INSERT INTO person (favoriteBall_id) VALUES (:favoriteBall_id)", </span><span class="cx"> {'favoriteBall_id': None} </span><span class="lines">@@ -329,8 +330,8 @@ </span><span class="cx"> lambda ctx:{'favoriteBall_id':p.favorateBall.id,'person_id':p.id} </span><span class="cx"> ) </span><span class="cx"> ]) </span><del>- objectstore.delete(p) - self.assert_sql(db, lambda: objectstore.get_session().flush(), [ </del><ins>+ sess.delete(p) + self.assert_sql(db, lambda: sess.flush(), [ </ins><span class="cx"> # heres the post update (which is a pre-update with deletes) </span><span class="cx"> ( </span><span class="cx"> "UPDATE person SET favoriteBall_id=:favoriteBall_id WHERE person.id = :person_id", </span><span class="lines">@@ -377,7 +378,10 @@ </span><span class="cx"> b4 = Ball() </span><span class="cx"> p.balls.append(b4) </span><span class="cx"> p.favorateBall = b </span><del>- self.assert_sql(db, lambda: objectstore.get_session().flush(), [ </del><ins>+ sess = create_session() + [sess.save(x) for x in [b,p,b2,b3,b4]] + + self.assert_sql(db, lambda: sess.flush(), [ </ins><span class="cx"> ( </span><span class="cx"> "INSERT INTO ball (person_id) VALUES (:person_id)", </span><span class="cx"> {'person_id':None} </span><span class="lines">@@ -455,8 +459,8 @@ </span><span class="cx"> ), </span><span class="cx"> ]) </span><span class="cx"> </span><del>- objectstore.delete(p) - self.assert_sql(db, lambda: objectstore.get_session().flush(), [ </del><ins>+ sess.delete(p) + self.assert_sql(db, lambda: sess.flush(), [ </ins><span class="cx"> ( </span><span class="cx"> "UPDATE ball SET person_id=:person_id WHERE ball.id = :ball_id", </span><span class="cx"> lambda ctx:{'person_id': None, 'ball_id': b.id} </span></span></pre></div> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1481 => 1482)</h4> <pre class="diff"><... [truncated message content] |