[Sqlalchemy-commits] [1484] sqlalchemy/branches/schema/test: fixes to circular dependency sort, unit
Brought to you by:
zzzeek
From: <co...@sq...> - 2006-05-22 01:14:57
|
<!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>[1484] sqlalchemy/branches/schema/test: fixes to circular dependency sort, unittests for pg...tweaks for getting zblog going</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1484</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-05-21 20:14:42 -0500 (Sun, 21 May 2006)</dd> </dl> <h3>Log Message</h3> <pre>fixes to circular dependency sort, unittests for pg...tweaks for getting zblog going</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasespostgrespy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyextactivemapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.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="#sqlalchemybranchesschemalibsqlalchemyormunitofworkpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py</a></li> <li><a href="#sqlalchemybranchesschematestactivemapperpy">sqlalchemy/branches/schema/test/activemapper.py</a></li> <li><a href="#sqlalchemybranchesschematestindexespy">sqlalchemy/branches/schema/test/indexes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -274,7 +274,7 @@ </span><span class="cx"> return self.module </span><span class="cx"> </span><span class="cx"> def has_table(self, connection, table_name): </span><del>- cursor = connection.execute("""select relname from pg_class where relname = %(name)s""", {'name':table_name}) </del><ins>+ cursor = connection.execute("""select relname from pg_class where lower(relname) = %(name)s""", {'name':table_name.lower()}) </ins><span class="cx"> return bool( not not cursor.rowcount ) </span><span class="cx"> </span><span class="cx"> def reflecttable(self, connection, table): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyextactivemapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ext/activemapper.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -177,4 +177,7 @@ </span><span class="cx"> def create_tables(): </span><span class="cx"> for metadata in ActiveMapperMeta.metadatas: </span><span class="cx"> metadata.create_all() </span><ins>+def drop_tables(): + for metadata in ActiveMapperMeta.metadatas: + metadata.drop_all() </ins><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -513,10 +513,10 @@ </span><span class="cx"> """called by a UnitOfWork object to save objects, which involves either an INSERT or </span><span class="cx"> an UPDATE statement for each table used by this mapper, for each element of the </span><span class="cx"> list.""" </span><del>- #print "SAVE_OBJ MAPPER", self.class_.__name__, objects </del><ins>+ print "SAVE_OBJ MAPPER", self.class_.__name__, objects </ins><span class="cx"> connection = uow.transaction.connection(self) </span><span class="cx"> for table in self.tables: </span><del>- #print "SAVE_OBJ table ", self.class_.__name__, table.name </del><ins>+ print "SAVE_OBJ table ", self.class_.__name__, table.name </ins><span class="cx"> # looping through our set of tables, which are all "real" tables, as opposed </span><span class="cx"> # to our main table which might be a select statement or something non-writeable </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -347,7 +347,12 @@ </span><span class="cx"> self._register_dirty(object) </span><span class="cx"> else: </span><span class="cx"> self._register_clean(object) </span><del>- </del><ins>+ + def _register_changed(self, obj): + if hasattr(obj, '_instance_key'): + self._register_dirty(obj) + else: + self._register_new(obj) </ins><span class="cx"> def _register_new(self, obj): </span><span class="cx"> self._attach(obj) </span><span class="cx"> self.uow.register_new(obj) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -45,7 +45,7 @@ </span><span class="cx"> def do_value_changed(self, obj, key, item, listval, isdelete): </span><span class="cx"> sess = object_session(obj) </span><span class="cx"> if sess is not None: </span><del>- sess._register_dirty(obj) </del><ins>+ sess._register_changed(obj) </ins><span class="cx"> if self.cascade is not None: </span><span class="cx"> if not isdelete: </span><span class="cx"> if self.cascade.save_update: </span><span class="lines">@@ -64,7 +64,7 @@ </span><span class="cx"> obj = self.obj </span><span class="cx"> sess = object_session(obj) </span><span class="cx"> if sess is not None: </span><del>- sess._register_dirty(obj) </del><ins>+ sess._register_changed(obj) </ins><span class="cx"> if newvalue is not None and self.cascade is not None: </span><span class="cx"> if self.cascade.save_update: </span><span class="cx"> sess.save_or_update(newvalue) </span><span class="lines">@@ -279,7 +279,7 @@ </span><span class="cx"> refreshed/updated to reflect a recent save/upcoming delete operation, but not a full </span><span class="cx"> save/delete operation on the object itself, unless an additional save/delete </span><span class="cx"> registration is entered for the object.""" </span><del>- #print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) </del><ins>+ print "REGISTER", repr(obj), repr(getattr(obj, '_instance_key', None)), str(isdelete), str(listonly) </ins><span class="cx"> # things can get really confusing if theres duplicate instances floating around, </span><span class="cx"> # so make sure everything is OK </span><span class="cx"> self.uow._validate_obj(obj) </span><span class="lines">@@ -542,9 +542,8 @@ </span><span class="cx"> </span><span class="cx"> this is not the normal case; this logic only kicks in when something like </span><span class="cx"> a hierarchical tree is being represented. </span><del>- - TODO: dont understand this code ? well neither do I ! it takes me - an hour to re-understand this code completely, which is definitely an issue. </del><ins>+ + TODO: refactor heavily </ins><span class="cx"> """ </span><span class="cx"> </span><span class="cx"> allobjects = [] </span><span class="lines">@@ -552,24 +551,15 @@ </span><span class="cx"> allobjects += task.objects.keys() </span><span class="cx"> tuples = [] </span><span class="cx"> </span><del>- objecttotask = {} - </del><span class="cx"> cycles = Set(cycles) </span><span class="cx"> </span><ins>+ print "BEGIN CIRC SORT-------" </ins><span class="cx"> # dependency processors that arent part of the cyclical thing </span><span class="cx"> # get put here </span><span class="cx"> extradeplist = [] </span><span class="cx"> </span><del>- # this creates a map of UOWTasks mapped to individual objects. - def get_object_task(parent, obj): - try: - return objecttotask[obj] - except KeyError: - t = UOWTask(None, parent.mapper) - t.parent = parent - objecttotask[obj] = t - return t - </del><ins>+ object_to_original_task = {} + </ins><span class="cx"> # this creates a map of UOWTasks mapped to a particular object </span><span class="cx"> # and a particular dependency processor. </span><span class="cx"> dependencies = {} </span><span class="lines">@@ -588,8 +578,7 @@ </span><span class="cx"> </span><span class="cx"> # work out a list of all the "dependency processors" that </span><span class="cx"> # represent objects that have to be dependency sorted at the </span><del>- # per-object level. all other dependency processors go in - # "extradep." </del><ins>+ # per-object level. </ins><span class="cx"> deps_by_targettask = {} </span><span class="cx"> for task in cycles: </span><span class="cx"> for dep in task.dependencies: </span><span class="lines">@@ -601,11 +590,9 @@ </span><span class="cx"> for task in cycles: </span><span class="cx"> for taskelement in task.objects.values(): </span><span class="cx"> obj = taskelement.obj </span><ins>+ object_to_original_task[obj] = task </ins><span class="cx"> #print "OBJ", repr(obj), "TASK", repr(task) </span><span class="cx"> </span><del>- # create a placeholder UOWTask that may be built into the final - # task tree - get_object_task(task, obj) </del><span class="cx"> for dep in deps_by_targettask.get(task, []): </span><span class="cx"> (processor, targettask, isdelete) = (dep.processor, dep.targettask, dep.isdeletefrom) </span><span class="cx"> if taskelement.isdelete is not dep.isdeletefrom: </span><span class="lines">@@ -635,9 +622,7 @@ </span><span class="cx"> if isdelete: </span><span class="cx"> childtask.append(o, processor.cascade.delete) </span><span class="cx"> if cyclicaldep: </span><del>- # cyclical, so create a placeholder UOWTask that may be built into the - # final task tree - t = get_object_task(childtask, o) </del><ins>+ object_to_original_task[o] = task </ins><span class="cx"> if not cyclicaldep: </span><span class="cx"> # not cyclical, so we are done with this </span><span class="cx"> continue </span><span class="lines">@@ -648,9 +633,9 @@ </span><span class="cx"> # then locate a UOWDependencyProcessor to add the object onto, which </span><span class="cx"> # will handle the modifications between saves/deletes </span><span class="cx"> if whosdep[0] is obj: </span><del>- get_dependency_task(whosdep[0], dep).append(whosdep[0], isdelete=isdelete) </del><ins>+ get_dependency_task(obj, dep).append(whosdep[0], isdelete=isdelete) </ins><span class="cx"> else: </span><del>- get_dependency_task(whosdep[0], dep).append(whosdep[1], isdelete=isdelete) </del><ins>+ get_dependency_task(obj, dep).append(whosdep[1], isdelete=isdelete) </ins><span class="cx"> else: </span><span class="cx"> get_dependency_task(obj, dep).append(obj, isdelete=isdelete) </span><span class="cx"> </span><span class="lines">@@ -658,18 +643,30 @@ </span><span class="cx"> if head is None: </span><span class="cx"> return None </span><span class="cx"> </span><del>- #print str(head) </del><ins>+ print str(head) </ins><span class="cx"> </span><ins>+ hierarchical_tasks = {} + def get_object_task(obj): + try: + return hierarchical_tasks[obj] + except KeyError: + originating_task = object_to_original_task[obj] + return hierarchical_tasks.setdefault(obj, UOWTask(None, originating_task.mapper)) + </ins><span class="cx"> def make_task_tree(node, parenttask): </span><span class="cx"> """takes a dependency-sorted tree of objects and creates a tree of UOWTasks""" </span><del>- t = objecttotask[node.item] </del><ins>+ print "MAKETASKTREE", node.item + t = get_object_task(node.item) </ins><span class="cx"> can_add_to_parent = t.mapper is parenttask.mapper </span><del>- if t.parent.objects.has_key(node.item): </del><ins>+ original_task = object_to_original_task[node.item] + if original_task.objects.has_key(node.item): </ins><span class="cx"> if can_add_to_parent: </span><del>- parenttask.append(node.item, t.parent.objects[node.item].listonly, isdelete=t.parent.objects[node.item].isdelete, childtask=t) </del><ins>+ parenttask.append(node.item, original_task.objects[node.item].listonly, isdelete=original_task.objects[node.item].isdelete, childtask=t) </ins><span class="cx"> else: </span><del>- t.append(node.item, t.parent.objects[node.item].listonly, isdelete=t.parent.objects[node.item].isdelete) - parenttask.append(None, listonly=False, isdelete=t.parent.objects[node.item].isdelete, childtask=t) </del><ins>+ t.append(node.item, original_task.objects[node.item].listonly, isdelete=original_task.objects[node.item].isdelete) + parenttask.append(None, listonly=False, isdelete=original_task.objects[node.item].isdelete, childtask=t) + else: + parenttask.append(None, childtask=t) </ins><span class="cx"> if dependencies.has_key(node.item): </span><span class="cx"> for depprocessor, deptask in dependencies[node.item].iteritems(): </span><span class="cx"> if can_add_to_parent: </span><span class="lines">@@ -688,6 +685,8 @@ </span><span class="cx"> t.dependencies += [d for d in extradeplist] </span><span class="cx"> t.childtasks = self.childtasks </span><span class="cx"> make_task_tree(head, t) </span><ins>+ print [o.obj for o in t.objects.values()] + print t.dump() </ins><span class="cx"> return t </span><span class="cx"> </span><span class="cx"> def dump(self): </span></span></pre></div> <a id="sqlalchemybranchesschematestactivemapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/activemapper.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/activemapper.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/test/activemapper.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -63,6 +63,7 @@ </span><span class="cx"> </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> clear_mappers() </span><ins>+ activemapper.drop_tables() </ins><span class="cx"> </span><span class="cx"> def tearDown(self): </span><span class="cx"> for t in activemapper.metadata.table_iterator(reverse=True): </span></span></pre></div> <a id="sqlalchemybranchesschematestindexespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/indexes.py (1483 => 1484)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/indexes.py 2006-05-21 22:36:53 UTC (rev 1483) +++ sqlalchemy/branches/schema/test/indexes.py 2006-05-22 01:14:42 UTC (rev 1484) </span><span class="lines">@@ -5,59 +5,51 @@ </span><span class="cx"> class IndexTest(testbase.AssertMixin): </span><span class="cx"> </span><span class="cx"> def setUp(self): </span><del>- self.created = [] </del><ins>+ global metadata + metadata = BoundMetaData(testbase.db) </ins><span class="cx"> self.echo = testbase.db.echo </span><span class="cx"> self.logger = testbase.db.logger </span><span class="cx"> </span><span class="cx"> def tearDown(self): </span><span class="cx"> testbase.db.echo = self.echo </span><span class="cx"> testbase.db.logger = testbase.db.engine.logger = self.logger </span><del>- if self.created: - self.created.reverse() - for entity in self.created: - entity.drop() </del><ins>+ metadata.drop_all() </ins><span class="cx"> </span><span class="cx"> def test_index_create(self): </span><del>- employees = Table('employees', testbase.metadata, </del><ins>+ employees = Table('employees', metadata, </ins><span class="cx"> Column('id', Integer, primary_key=True), </span><span class="cx"> Column('first_name', String(30)), </span><span class="cx"> Column('last_name', String(30)), </span><span class="cx"> Column('email_address', String(30))) </span><span class="cx"> employees.create() </span><del>- self.created.append(employees) </del><span class="cx"> </span><span class="cx"> i = Index('employee_name_index', </span><span class="cx"> employees.c.last_name, employees.c.first_name) </span><span class="cx"> i.create() </span><del>- self.created.append(i) </del><span class="cx"> assert employees.indexes['employee_name_index'] is i </span><span class="cx"> </span><span class="cx"> i2 = Index('employee_email_index', </span><span class="cx"> employees.c.email_address, unique=True) </span><span class="cx"> i2.create() </span><del>- self.created.append(i2) </del><span class="cx"> assert employees.indexes['employee_email_index'] is i2 </span><span class="cx"> </span><span class="cx"> def test_index_create_camelcase(self): </span><span class="cx"> """test that mixed-case index identifiers are legal""" </span><del>- employees = Table('companyEmployees', testbase.metadata, </del><ins>+ employees = Table('companyEmployees', metadata, </ins><span class="cx"> Column('id', Integer, primary_key=True), </span><span class="cx"> Column('firstName', String(30)), </span><span class="cx"> Column('lastName', String(30)), </span><span class="cx"> Column('emailAddress', String(30))) </span><span class="cx"> </span><span class="cx"> employees.create() </span><del>- self.created.append(employees) </del><span class="cx"> </span><span class="cx"> i = Index('employeeNameIndex', </span><span class="cx"> employees.c.lastName, employees.c.firstName) </span><span class="cx"> i.create() </span><del>- self.created.append(i) </del><span class="cx"> </span><span class="cx"> i = Index('employeeEmailIndex', </span><span class="cx"> employees.c.emailAddress, unique=True) </span><span class="cx"> i.create() </span><del>- self.created.append(i) </del><span class="cx"> </span><span class="cx"> # Check that the table is useable. This is mostly for pg, </span><span class="cx"> # which can be somewhat sticky with mixed-case identifiers </span><span class="lines">@@ -76,7 +68,7 @@ </span><span class="cx"> stream.write = capt.append </span><span class="cx"> testbase.db.logger = testbase.db.engine.logger = stream </span><span class="cx"> </span><del>- events = Table('events', testbase.metadata, </del><ins>+ events = Table('events', metadata, </ins><span class="cx"> Column('id', Integer, primary_key=True), </span><span class="cx"> Column('name', String(30), unique=True), </span><span class="cx"> Column('location', String(30), index=True), </span><span class="lines">@@ -94,7 +86,6 @@ </span><span class="cx"> assert len(index_names) == 4 </span><span class="cx"> </span><span class="cx"> events.create() </span><del>- self.created.append(events) </del><span class="cx"> </span><span class="cx"> # verify that the table is functional </span><span class="cx"> events.insert().execute(id=1, name='hockey finals', location='rink', </span></span></pre> </div> </div> </body> </html> |