sqlalchemy-commits Mailing List for SQLAlchemy (Page 364)
Brought to you by:
zzzeek
You can subscribe to this list here.
2006 |
Jan
|
Feb
(74) |
Mar
(167) |
Apr
(127) |
May
(190) |
Jun
(119) |
Jul
(77) |
Aug
(82) |
Sep
(84) |
Oct
(153) |
Nov
(45) |
Dec
(54) |
---|---|---|---|---|---|---|---|---|---|---|---|---|
2007 |
Jan
(109) |
Feb
(80) |
Mar
(110) |
Apr
(106) |
May
(92) |
Jun
(147) |
Jul
(288) |
Aug
(307) |
Sep
(108) |
Oct
(156) |
Nov
(147) |
Dec
(134) |
2008 |
Jan
(126) |
Feb
(91) |
Mar
(184) |
Apr
(208) |
May
(212) |
Jun
(54) |
Jul
(106) |
Aug
(80) |
Sep
(58) |
Oct
(80) |
Nov
(119) |
Dec
(220) |
2009 |
Jan
(202) |
Feb
(50) |
Mar
(70) |
Apr
(46) |
May
(80) |
Jun
(61) |
Jul
(146) |
Aug
(81) |
Sep
(71) |
Oct
(74) |
Nov
(66) |
Dec
(82) |
2010 |
Jan
(112) |
Feb
(169) |
Mar
(235) |
Apr
(77) |
May
(22) |
Jun
(31) |
Jul
(46) |
Aug
(46) |
Sep
(70) |
Oct
(36) |
Nov
(37) |
Dec
(79) |
2011 |
Jan
(46) |
Feb
(54) |
Mar
(65) |
Apr
(73) |
May
(31) |
Jun
(46) |
Jul
(40) |
Aug
(36) |
Sep
(44) |
Oct
(33) |
Nov
(19) |
Dec
(10) |
2012 |
Jan
(60) |
Feb
(37) |
Mar
(35) |
Apr
(28) |
May
(27) |
Jun
(50) |
Jul
(33) |
Aug
(88) |
Sep
(64) |
Oct
(74) |
Nov
(62) |
Dec
(41) |
2013 |
Jan
(30) |
Feb
(37) |
Mar
(39) |
Apr
(52) |
May
(40) |
Jun
(85) |
Jul
(74) |
Aug
(76) |
Sep
(26) |
Oct
(76) |
Nov
(63) |
Dec
(65) |
2014 |
Jan
(68) |
Feb
(82) |
Mar
(87) |
Apr
(24) |
May
(66) |
Jun
(34) |
Jul
(86) |
Aug
(75) |
Sep
(70) |
Oct
(41) |
Nov
(23) |
Dec
(53) |
2015 |
Jan
(40) |
Feb
(39) |
Mar
(69) |
Apr
(64) |
May
(40) |
Jun
(43) |
Jul
(20) |
Aug
(48) |
Sep
(38) |
Oct
(28) |
Nov
(34) |
Dec
(44) |
2016 |
Jan
(82) |
Feb
(49) |
Mar
(25) |
Apr
(21) |
May
(19) |
Jun
(46) |
Jul
(38) |
Aug
(21) |
Sep
(33) |
Oct
(44) |
Nov
(26) |
Dec
(10) |
2017 |
Jan
(52) |
Feb
(18) |
Mar
(61) |
Apr
(43) |
May
(57) |
Jun
(36) |
Jul
(37) |
Aug
|
Sep
|
Oct
|
Nov
|
Dec
|
From: <co...@sq...> - 2006-04-29 19:42:29
|
<!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>[1361] sqlalchemy/branches/schema/lib/sqlalchemy/orm: various stuff</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1361</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 14:42:15 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>various stuff</pre> <h3>Modified Paths</h3> <ul> <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> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemymodsthreadlocalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py (1360 => 1361)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-04-29 19:28:47 UTC (rev 1360) +++ sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-04-29 19:42:15 UTC (rev 1361) </span><span class="lines">@@ -90,6 +90,7 @@ </span><span class="cx"> class_.__init__ = __init__ </span><span class="cx"> m = mapper(class_, *args, **params) </span><span class="cx"> class_.mapper = m </span><ins>+ # TODO: get these outta here, have to go off explicit session </ins><span class="cx"> class_.get = m.get </span><span class="cx"> class_.select = m.select </span><span class="cx"> class_.select_by = m.select_by </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1360 => 1361)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 19:28:47 UTC (rev 1360) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 19:42:15 UTC (rev 1361) </span><span class="lines">@@ -247,7 +247,6 @@ </span><span class="cx"> if getattr(prop, 'key', None) is None: </span><span class="cx"> prop.init(key, self) </span><span class="cx"> </span><del>- </del><span class="cx"> # this prints a summary of the object attributes and how they </span><span class="cx"> # will be mapped to table columns </span><span class="cx"> #print "mapper %s, columntoproperty:" % (self.class_.__name__) </span><span class="lines">@@ -603,7 +602,6 @@ </span><span class="cx"> if value is not None: </span><span class="cx"> params[col.key] = value </span><span class="cx"> elif self.effective_polymorphic_on is not None and col.original is self.effective_polymorphic_on.original: </span><del>- print "YA YA ITS", self.polymorphic_ident </del><span class="cx"> if isinsert: </span><span class="cx"> value = self.polymorphic_ident </span><span class="cx"> if col.default is None or value is not None: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1360 => 1361)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-29 19:28:47 UTC (rev 1360) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-29 19:42:15 UTC (rev 1361) </span><span class="lines">@@ -270,7 +270,7 @@ </span><span class="cx"> self.save_or_update(c, entity_name=entity_name) </span><span class="cx"> </span><span class="cx"> def update(self, object, entity_name=None): </span><del>- """Brings the given detached (saved) instance. into this Session. </del><ins>+ """Brings the given detached (saved) instance into this Session. </ins><span class="cx"> If there is a persistent instance with the same identifier (i.e. a saved instance already associated with this </span><span class="cx"> Session), an exception is thrown. </span><span class="cx"> This operation cascades the "save_or_update" method to associated instances if the relation is mapped </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 19:28:58
|
<!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>[1360] sqlalchemy/branches/schema/test: mapper is not supposed to register_clean() prematurely..</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1360</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 14:28:47 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>mapper is not supposed to register_clean() prematurely..</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1359 => 1360)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 18:41:13 UTC (rev 1359) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 19:28:47 UTC (rev 1360) </span><span class="lines">@@ -411,7 +411,9 @@ </span><span class="cx"> if not nohist: </span><span class="cx"> session._register_new(self) </span><span class="cx"> else: </span><del>- session._register_clean(self) </del><ins>+ pass + # TODO: this _attach should not be needed.... + #session._attach(self) </ins><span class="cx"> if oldinit is not None: </span><span class="cx"> oldinit(self, *args, **kwargs) </span><span class="cx"> # override oldinit, insuring that its not already one of our </span><span class="lines">@@ -784,7 +786,6 @@ </span><span class="cx"> identitykey = self._identity_key(row) </span><span class="cx"> if session.has_key(identitykey): </span><span class="cx"> instance = session._get(identitykey) </span><del>- </del><span class="cx"> isnew = False </span><span class="cx"> if populate_existing or session.is_expired(instance, unexpire=True): </span><span class="cx"> if not imap.has_key(identitykey): </span><span class="lines">@@ -836,7 +837,8 @@ </span><span class="cx"> # in order to save on KeyErrors later on </span><span class="cx"> sessionlib.global_attributes.init_attr(obj) </span><span class="cx"> </span><del>- session._register_clean(obj) </del><ins>+# TODO: this _attach should not be needed.... +# session._attach(obj) </ins><span class="cx"> return obj </span><span class="cx"> </span><span class="cx"> def translate_row(self, tomapper, row): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1359 => 1360)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-29 18:41:13 UTC (rev 1359) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-29 19:28:47 UTC (rev 1360) </span><span class="lines">@@ -591,7 +591,6 @@ </span><span class="cx"> result_list = h </span><span class="cx"> else: </span><span class="cx"> result_list = getattr(instance, self.key) </span><del>- </del><span class="cx"> self._instance(session, row, imap, result_list) </span><span class="cx"> </span><span class="cx"> def _create_decorator_row(self): </span></span></pre></div> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1359 => 1360)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/mapper.py 2006-04-29 18:41:13 UTC (rev 1359) +++ sqlalchemy/branches/schema/test/mapper.py 2006-04-29 19:28:47 UTC (rev 1360) </span><span class="lines">@@ -614,7 +614,6 @@ </span><span class="cx"> class EagerTest(MapperSuperTest): </span><span class="cx"> def testbasic(self): </span><span class="cx"> """tests a basic one-to-many eager load""" </span><del>- </del><span class="cx"> m = mapper(Address, addresses) </span><span class="cx"> </span><span class="cx"> m = mapper(User, users, properties = dict( </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 18:41:27
|
<!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>[1359] sqlalchemy/branches/schema/lib/sqlalchemy: vertical example, session stuff</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1359</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 13:41:13 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>vertical example, session stuff</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschemaexamplesverticalverticalpy">sqlalchemy/branches/schema/examples/vertical/vertical.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemy__init__py">sqlalchemy/branches/schema/lib/sqlalchemy/__init__.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyattributespy">sqlalchemy/branches/schema/lib/sqlalchemy/attributes.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="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormquerypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.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="#sqlalchemybranchesschemalibsqlalchemyormutilpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/util.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -130,7 +130,6 @@ </span><span class="cx"> session.delete(c) </span><span class="cx"> session.flush() </span><span class="cx"> </span><del>- </del><span class="cx"> managers.drop() </span><span class="cx"> engineers.drop() </span><span class="cx"> people.drop() </span></span></pre></div> <a id="sqlalchemybranchesschemaexamplesverticalverticalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/vertical/vertical.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/vertical/vertical.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/examples/vertical/vertical.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -5,7 +5,7 @@ </span><span class="cx"> represented in distinct database rows. This allows objects to be created with dynamically changing </span><span class="cx"> fields that are all persisted in a normalized fashion.""" </span><span class="cx"> </span><del>-e = create_engine('sqlite://', echo=True) </del><ins>+e = BoundMetaData('sqlite://', echo=True) </ins><span class="cx"> </span><span class="cx"> # this table represents Entity objects. each Entity gets a row in this table, </span><span class="cx"> # with a primary key and a title. </span><span class="lines">@@ -48,13 +48,15 @@ </span><span class="cx"> object's _entities dictionary for the appropriate value, and the __setattribute__ </span><span class="cx"> method is overridden to set all non "_" attributes as EntityValues within the </span><span class="cx"> _entities dictionary. """ </span><del>- def __init__(self): - """the constructor sets the "_entities" member to an EntityDict. A mapper - will wrap this property with its own history-list object.""" - self._entities = EntityDict() </del><ins>+ + # establish the type of '_entities' + _entities = EntityDict + </ins><span class="cx"> def __getattr__(self, key): </span><span class="cx"> """getattr proxies requests for attributes which dont 'exist' on the object </span><span class="cx"> to the underying _entities dictionary.""" </span><ins>+ if key[0] == '_': + return super(Entity, self).__getattr__(key) </ins><span class="cx"> try: </span><span class="cx"> return self._entities[key].value </span><span class="cx"> except KeyError: </span><span class="lines">@@ -88,7 +90,10 @@ </span><span class="cx"> the value to the underlying datatype of its EntityField.""" </span><span class="cx"> def __init__(self, key=None, value=None): </span><span class="cx"> if key is not None: </span><del>- self.field = class_mapper(EntityField).get_by(name=key) or EntityField(key) </del><ins>+ sess = create_session() + self.field = sess.query(EntityField).get_by(name=key) or EntityField(key) + # close the session, which will make a loaded EntityField a detached instance + sess.close() </ins><span class="cx"> if self.field.datatype is None: </span><span class="cx"> if isinstance(value, int): </span><span class="cx"> self.field.datatype = 'int' </span><span class="lines">@@ -114,16 +119,17 @@ </span><span class="cx"> mapper( </span><span class="cx"> EntityValue, entity_values, </span><span class="cx"> properties = { </span><del>- 'field' : relation(EntityField, lazy=False) </del><ins>+ 'field' : relation(EntityField, lazy=False, cascade='all') </ins><span class="cx"> } </span><span class="cx"> ) </span><span class="cx"> </span><del>-entitymapper = mapper(Entity, entities, properties = { - '_entities' : relation(EntityValue, lazy=False) </del><ins>+mapper(Entity, entities, properties = { + '_entities' : relation(EntityValue, lazy=False, cascade='save-update') </ins><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> # create two entities. the objects can be used about as regularly as </span><span class="cx"> # any object can. </span><ins>+session = create_session() </ins><span class="cx"> entity = Entity() </span><span class="cx"> entity.title = 'this is the first entity' </span><span class="cx"> entity.name = 'this is the name' </span><span class="lines">@@ -137,14 +143,15 @@ </span><span class="cx"> entity2.data = ('hoo', 'ha') </span><span class="cx"> </span><span class="cx"> # commit </span><del>-objectstore.commit() </del><ins>+[session.save(x) for x in (entity, entity2)] +session.flush() </ins><span class="cx"> </span><span class="cx"> # we would like to illustate loading everything totally clean from </span><del>-# the database, so we clear out the objectstore. -objectstore.clear() </del><ins>+# the database, so we clear out the session +session.clear() </ins><span class="cx"> </span><span class="cx"> # select both objects and print </span><del>-entities = entitymapper.select() </del><ins>+entities = session.query(Entity).select() </ins><span class="cx"> for entity in entities: </span><span class="cx"> print entity.title, entity.name, entity.price, entity.data </span><span class="cx"> </span><span class="lines">@@ -152,13 +159,19 @@ </span><span class="cx"> entities[0].price=90 </span><span class="cx"> entities[0].title = 'another new title' </span><span class="cx"> entities[1].data = {'oof':5,'lala':8} </span><ins>+entity3 = Entity() +entity3.title = 'third entity' +entity3.name = 'new name' +entity3.price = '$1.95' +entity3.data = 'some data' +session.save(entity3) </ins><span class="cx"> </span><span class="cx"> # commit changes. the correct rows are updated, nothing else. </span><del>-objectstore.commit() </del><ins>+session.flush() </ins><span class="cx"> </span><del>-# lets see if that one came through. clear object store, re-select </del><ins>+# lets see if that one came through. clear the session, re-select </ins><span class="cx"> # and print </span><del>-objectstore.clear() -entities = entitymapper.select() </del><ins>+session.clear() +entities = session.query(Entity).select() </ins><span class="cx"> for entity in entities: </span><span class="cx"> print entity.title, entity.name, entity.price, entity.data </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemy__init__py"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/__init__.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/__init__.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/__init__.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -14,7 +14,7 @@ </span><span class="cx"> from sqlalchemy.orm import * </span><span class="cx"> import sqlalchemy.ext.proxy </span><span class="cx"> </span><del>-from sqlalchemy.orm.session import Session, get_session </del><ins>+from sqlalchemy.orm.session import Session, current_session </ins><span class="cx"> </span><span class="cx"> create_engine = sqlalchemy.engine.create_engine </span><span class="cx"> create_session = sqlalchemy.orm.session.Session </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/attributes.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -37,11 +37,12 @@ </span><span class="cx"> create_prop method on AttributeManger, which can be overridden to provide </span><span class="cx"> subclasses of SmartProperty. </span><span class="cx"> """ </span><del>- def __init__(self, manager, key, uselist, callable_, **kwargs): </del><ins>+ def __init__(self, manager, key, uselist, callable_, typecallable, **kwargs): </ins><span class="cx"> self.manager = manager </span><span class="cx"> self.key = key </span><span class="cx"> self.uselist = uselist </span><span class="cx"> self.callable_ = callable_ </span><ins>+ self.typecallable= typecallable </ins><span class="cx"> self.kwargs = kwargs </span><span class="cx"> def init(self, obj, attrhist=None): </span><span class="cx"> """creates an appropriate ManagedAttribute for the given object and establishes </span><span class="lines">@@ -50,7 +51,7 @@ </span><span class="cx"> func = self.callable_(obj) </span><span class="cx"> else: </span><span class="cx"> func = None </span><del>- return self.manager.create_managed_attribute(obj, self.key, self.uselist, callable_=func, attrdict=attrhist, **self.kwargs) </del><ins>+ return self.manager.create_managed_attribute(obj, self.key, self.uselist, callable_=func, attrdict=attrhist, typecallable=self.typecallable, **self.kwargs) </ins><span class="cx"> def __set__(self, obj, value): </span><span class="cx"> self.manager.set_attribute(obj, self.key, value) </span><span class="cx"> def __delete__(self, obj): </span><span class="lines">@@ -173,7 +174,7 @@ </span><span class="cx"> This is the "list history container" object. </span><span class="cx"> Subclasses util.HistoryArraySet to provide "onchange" event handling as well </span><span class="cx"> as a plugin point for BackrefExtension objects.""" </span><del>- def __init__(self, obj, key, data=None, extension=None, trackparent=False, **kwargs): </del><ins>+ def __init__(self, obj, key, data=None, extension=None, trackparent=False, typecallable=None, **kwargs): </ins><span class="cx"> ManagedAttribute.__init__(self, obj, key) </span><span class="cx"> self.extension = extension </span><span class="cx"> self.trackparent = trackparent </span><span class="lines">@@ -189,10 +190,11 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> if data is not None: </span><span class="cx"> list_ = data </span><ins>+ elif typecallable is not None: + list_ = typecallable() </ins><span class="cx"> else: </span><span class="cx"> list_ = [] </span><del>- obj.__dict__[key] = [] - </del><ins>+ obj.__dict__[key] = list_ </ins><span class="cx"> util.HistoryArraySet.__init__(self, list_, readonly=kwargs.get('readonly', False)) </span><span class="cx"> def do_value_changed(self, obj, key, item, listval, isdelete): </span><span class="cx"> pass </span><span class="lines">@@ -334,16 +336,16 @@ </span><span class="cx"> upon an attribute change of value.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def create_prop(self, class_, key, uselist, callable_, **kwargs): </del><ins>+ def create_prop(self, class_, key, uselist, callable_, typecallable, **kwargs): </ins><span class="cx"> """creates a scalar property object, defaulting to SmartProperty, which </span><span class="cx"> will communicate change events back to this AttributeManager.""" </span><del>- return SmartProperty(self, key, uselist, callable_, **kwargs) </del><ins>+ return SmartProperty(self, key, uselist, callable_, typecallable, **kwargs) </ins><span class="cx"> def create_scalar(self, obj, key, **kwargs): </span><span class="cx"> return ScalarAttribute(obj, key, **kwargs) </span><del>- def create_list(self, obj, key, list_, **kwargs): </del><ins>+ def create_list(self, obj, key, list_, typecallable=None, **kwargs): </ins><span class="cx"> """creates a history-aware list property, defaulting to a ListAttribute which </span><span class="cx"> is a subclass of HistoryArrayList.""" </span><del>- return ListAttribute(obj, key, list_, **kwargs) </del><ins>+ return ListAttribute(obj, key, list_, typecallable=typecallable, **kwargs) </ins><span class="cx"> def create_callable(self, obj, key, func, uselist, **kwargs): </span><span class="cx"> """creates a callable container that will invoke a function the first </span><span class="cx"> time an object property is accessed. The return value of the function </span><span class="lines">@@ -491,15 +493,15 @@ </span><span class="cx"> def is_class_managed(self, class_, key): </span><span class="cx"> return hasattr(class_, key) and isinstance(getattr(class_, key), SmartProperty) </span><span class="cx"> </span><del>- def create_managed_attribute(self, obj, key, uselist, callable_=None, attrdict=None, **kwargs): </del><ins>+ def create_managed_attribute(self, obj, key, uselist, callable_=None, attrdict=None, typecallable=None, **kwargs): </ins><span class="cx"> """creates a new ManagedAttribute corresponding to the given attribute key on the </span><span class="cx"> given object instance, and installs it in the attribute dictionary attached to the object.""" </span><span class="cx"> if callable_ is not None: </span><del>- prop = self.create_callable(obj, key, callable_, uselist=uselist, **kwargs) </del><ins>+ prop = self.create_callable(obj, key, callable_, uselist=uselist, typecallable=typecallable, **kwargs) </ins><span class="cx"> elif not uselist: </span><span class="cx"> prop = self.create_scalar(obj, key, **kwargs) </span><span class="cx"> else: </span><del>- prop = self.create_list(obj, key, None, **kwargs) </del><ins>+ prop = self.create_list(obj, key, None, typecallable=typecallable, **kwargs) </ins><span class="cx"> if attrdict is None: </span><span class="cx"> attrdict = self.attribute_history(obj) </span><span class="cx"> attrdict[key] = prop </span><span class="lines">@@ -521,7 +523,8 @@ </span><span class="cx"> if not hasattr(class_, '_attribute_manager'): </span><span class="cx"> class_._attribute_manager = self </span><span class="cx"> class_._managed_attributes = ObjectAttributeGateway() </span><del>- setattr(class_, key, self.create_prop(class_, key, uselist, callable_, **kwargs)) </del><ins>+ typecallable = getattr(class_, key, None) + setattr(class_, key, self.create_prop(class_, key, uselist, callable_, typecallable=typecallable, **kwargs)) </ins><span class="cx"> </span><span class="cx"> managed_attributes = weakref.WeakKeyDictionary() </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemymodsthreadlocalpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/mods/threadlocal.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -112,7 +112,7 @@ </span><span class="cx"> class_.expunge = expunge </span><span class="cx"> def install_plugin(): </span><span class="cx"> reg = util.ScopedRegistry(session.Session) </span><del>- session._default_session = lambda *args, **kwargs: reg() </del><ins>+ session.register_default_session(lambda *args, **kwargs: reg()) </ins><span class="cx"> engine.default_strategy = 'threadlocal' </span><span class="cx"> sqlalchemy.objectstore = Objectstore() </span><span class="cx"> sqlalchemy.assign_mapper = assign_mapper </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -406,15 +406,12 @@ </span><span class="cx"> if kwargs.has_key('_sa_session'): </span><span class="cx"> session = kwargs.pop('_sa_session') </span><span class="cx"> else: </span><del>- session = sessionlib.get_session(self, raiseerror=False) </del><ins>+ session = sessionlib.current_session(self) </ins><span class="cx"> if session is not None: </span><span class="cx"> if not nohist: </span><del>- # register new with the correct session, before the object's - # constructor is called, since further assignments within the - # constructor would otherwise bind it to whatever get_session() is. </del><span class="cx"> session._register_new(self) </span><span class="cx"> else: </span><del>- session._bind_to(self) </del><ins>+ session._register_clean(self) </ins><span class="cx"> if oldinit is not None: </span><span class="cx"> oldinit(self, *args, **kwargs) </span><span class="cx"> # override oldinit, insuring that its not already one of our </span><span class="lines">@@ -839,7 +836,7 @@ </span><span class="cx"> # in order to save on KeyErrors later on </span><span class="cx"> sessionlib.global_attributes.init_attr(obj) </span><span class="cx"> </span><del>- session._bind_to(obj) </del><ins>+ session._register_clean(obj) </ins><span class="cx"> return obj </span><span class="cx"> </span><span class="cx"> def translate_row(self, tomapper, row): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -75,7 +75,7 @@ </span><span class="cx"> if not self.parent.is_assigned(instance): </span><span class="cx"> return object_mapper(instance).props[self.key].setup_loader(instance) </span><span class="cx"> def lazyload(): </span><del>- session = sessionlib.get_session(instance) </del><ins>+ session = sessionlib.object_session(instance) </ins><span class="cx"> connection = session.connection(self.parent) </span><span class="cx"> clause = sql.and_() </span><span class="cx"> try: </span><span class="lines">@@ -210,7 +210,7 @@ </span><span class="cx"> else: </span><span class="cx"> if self.primaryjoin is None: </span><span class="cx"> self.primaryjoin = sql.join(parent.unjoined_table, self.target).onclause </span><del>- print "PJ", self.primaryjoin </del><ins>+ </ins><span class="cx"> # if the foreign key wasnt specified and theres no assocaition table, try to figure </span><span class="cx"> # out who is dependent on who. we dont need all the foreign keys represented in the join, </span><span class="cx"> # just one of them. </span><span class="lines">@@ -373,7 +373,7 @@ </span><span class="cx"> def lazyload(): </span><span class="cx"> params = {} </span><span class="cx"> allparams = True </span><del>- session = sessionlib.get_session(instance, raiseerror=False) </del><ins>+ session = sessionlib.object_session(instance) </ins><span class="cx"> #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds </span><span class="cx"> if session is not None: </span><span class="cx"> for col, bind in self.lazybinds.iteritems(): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -28,7 +28,7 @@ </span><span class="cx"> self._get_clause = self.mapper._get_clause </span><span class="cx"> def _get_session(self): </span><span class="cx"> if self._session is None: </span><del>- return sessionlib.get_session() </del><ins>+ return sessionlib.required_current_session() </ins><span class="cx"> else: </span><span class="cx"> return self._session </span><span class="cx"> table = property(lambda s:s.mapper.select_table) </span><span class="lines">@@ -40,9 +40,19 @@ </span><span class="cx"> if not found. The *ident argument is a </span><span class="cx"> list of primary key columns in the order of the table def's primary key columns.""" </span><span class="cx"> key = self.mapper.identity_key(*ident) </span><del>- print "key: " + repr(key) + " ident: " + repr(ident) </del><span class="cx"> return self._get(key, ident, **kwargs) </span><span class="cx"> </span><ins>+ def load(self, *ident, **kwargs): + """returns an instance of the object based on the given identifier. If not found, + raises an exception. The method will *remove all pending changes* to the object + already existing in the Session. The *ident argument is a + list of primary key columns in the order of the table def's primary key columns.""" + key = self.mapper.identity_key(*ident) + instance = self._get(key, ident, reload=True, **kwargs) + if instance is None: + raise exceptions.InvalidRequestError("No instance found for identity %s" % repr(ident)) + return instance + </ins><span class="cx"> def get_by(self, *args, **params): </span><span class="cx"> """returns a single object instance based on the given key/value criterion. </span><span class="cx"> this is either the first value in the result list, or None if the list is </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -60,7 +60,7 @@ </span><span class="cx"> if import_session is not None: </span><span class="cx"> self.uow = unitofwork.UnitOfWork(identity_map=import_session.uow.identity_map) </span><span class="cx"> elif new_imap is False: </span><del>- self.uow = unitofwork.UnitOfWork(identity_map=objectstore.get_session().uow.identity_map) </del><ins>+ self.uow = unitofwork.UnitOfWork(identity_map=current_session().uow.identity_map) </ins><span class="cx"> else: </span><span class="cx"> self.uow = unitofwork.UnitOfWork() </span><span class="cx"> </span><span class="lines">@@ -106,13 +106,21 @@ </span><span class="cx"> method will release the resources of the underlying Connection, otherwise its a no-op. </span><span class="cx"> """ </span><span class="cx"> return self.connection(mapper, close_with_result=True).execute(clause, params, **kwargs) </span><ins>+ </ins><span class="cx"> def close(self): </span><span class="cx"> """closes this Session. </span><del>- - TODO: what should we do here ? </del><span class="cx"> """ </span><ins>+ self.clear() </ins><span class="cx"> if self.transaction is not None: </span><span class="cx"> self.transaction.close() </span><ins>+ + def clear(self): + """removes all object instances from this Session. this is equivalent to calling expunge() for all + objects in this Session.""" + for instance in self: + self._unattach(instance) + self.uow = unitofwork.UnitOfWork() + </ins><span class="cx"> def mapper(self, class_, entity_name=None): </span><span class="cx"> """given an Class, returns the primary Mapper responsible for persisting it""" </span><span class="cx"> return class_mapper(class_, entity_name = entity_name) </span><span class="lines">@@ -213,14 +221,25 @@ </span><span class="cx"> self.uow.flush(self, objects) </span><span class="cx"> </span><span class="cx"> def get(self, class_, *ident, **kwargs): </span><del>- """given a class and a primary key identifier, loads the corresponding object.""" </del><ins>+ """returns an instance of the object based on the given identifier, or None + if not found. The *ident argument is a list of primary key columns in the order of the + table def's primary key columns. + + the entity_name keyword argument may also be specified which further qualifies the underlying + Mapper used to perform the query.""" </ins><span class="cx"> entity_name = kwargs.get('entity_name', None) </span><span class="cx"> return self.query(class_, entity_name=entity_name).get(*ident) </span><span class="cx"> </span><span class="cx"> def load(self, class_, *ident, **kwargs): </span><del>- """given a class and a primary key identifier, loads the corresponding object.""" </del><ins>+ """returns an instance of the object based on the given identifier. If not found, + raises an exception. The method will *remove all pending changes* to the object + already existing in the Session. The *ident argument is a + list of primary key columns in the order of the table def's primary key columns. + + the entity_name keyword argument may also be specified which further qualifies the underlying + Mapper used to perform the query.""" </ins><span class="cx"> entity_name = kwargs.get('entity_name', None) </span><del>- return self.query(class_, entity_name=entity_name).get(*ident) </del><ins>+ return self.query(class_, entity_name=entity_name).load(*ident) </ins><span class="cx"> </span><span class="cx"> def refresh(self, object): </span><span class="cx"> """reloads the attributes for the given object from the database, clears </span><span class="lines">@@ -237,10 +256,12 @@ </span><span class="cx"> self.uow.expunge(object) </span><span class="cx"> </span><span class="cx"> def save(self, object, entity_name=None): </span><del>- """adds an unsaved object to this Session. </del><ins>+ """ + Adds a transient (unsaved) instance to this Session. This operation cascades the "save_or_update" + method to associated instances if the relation is mapped with cascade="save-update". </ins><span class="cx"> </span><del>- The 'entity_name' keyword argument can also be given which will be assigned - to the instances if given. </del><ins>+ The 'entity_name' keyword argument will further qualify the specific Mapper used to handle this + instance. </ins><span class="cx"> """ </span><span class="cx"> for c in object_mapper(object, entity_name=entity_name).cascade_iterator('save-update', object): </span><span class="cx"> if c is object: </span><span class="lines">@@ -249,6 +270,11 @@ </span><span class="cx"> self.save_or_update(c, entity_name=entity_name) </span><span class="cx"> </span><span class="cx"> def update(self, object, entity_name=None): </span><ins>+ """Brings the given detached (saved) instance. into this Session. + If there is a persistent instance with the same identifier (i.e. a saved instance already associated with this + Session), an exception is thrown. + This operation cascades the "save_or_update" method to associated instances if the relation is mapped + with cascade="save-update".""" </ins><span class="cx"> for c in object_mapper(object, entity_name=entity_name).cascade_iterator('save-update', object): </span><span class="cx"> if c is o: </span><span class="cx"> self._update_impl(c, entity_name=entity_name) </span><span class="lines">@@ -263,11 +289,6 @@ </span><span class="cx"> else: </span><span class="cx"> self._update_impl(c, entity_name=entity_name) </span><span class="cx"> </span><del>- def clear(self): - """removes all object instances from this Session. this is equivalent to calling expunge() for all - objects in this Session.""" - self.uow = unitofwork.UnitOfWork() - </del><span class="cx"> def delete(self, object, entity_name=None): </span><span class="cx"> for c in object_mapper(object, entity_name=entity_name).cascade_iterator('delete', object): </span><span class="cx"> self.uow.register_deleted(c) </span><span class="lines">@@ -281,7 +302,7 @@ </span><span class="cx"> ident = mapper.identity(object) </span><span class="cx"> for k in ident: </span><span class="cx"> if k is None: </span><del>- raise InvalidRequestError("Instance '%s' does not have a full set of identity values, and does not represent a saved entity in the database. Use the add() method to add unsaved instances to this Session." % str(obj)) </del><ins>+ raise InvalidRequestError("Instance '%s' does not have a full set of identity values, and does not represent a saved entity in the database. Use the add() method to add unsaved instances to this Session." % repr(obj)) </ins><span class="cx"> key = mapper.identity_key(*ident) </span><span class="cx"> u = self.uow </span><span class="cx"> if u.identity_map.has_key(key): </span><span class="lines">@@ -297,7 +318,7 @@ </span><span class="cx"> def _save_impl(self, object, **kwargs): </span><span class="cx"> if hasattr(object, '_instance_key'): </span><span class="cx"> if not self.uow.has_key(object._instance_key): </span><del>- raise InvalidRequestError("Instance '%s' attached to a different Session" % repr(object)) </del><ins>+ raise InvalidRequestError("Instance '%s' is already persistent in a different Session" % repr(object)) </ins><span class="cx"> else: </span><span class="cx"> entity_name = kwargs.get('entity_name', None) </span><span class="cx"> if entity_name is not None: </span><span class="lines">@@ -306,7 +327,7 @@ </span><span class="cx"> self._register_new(object) </span><span class="cx"> </span><span class="cx"> def _update_impl(self, object, **kwargs): </span><del>- if self._is_bound(object) and object not in self.deleted: </del><ins>+ if self._is_attached(object) and object not in self.deleted: </ins><span class="cx"> return </span><span class="cx"> if not hasattr(object, '_instance_key'): </span><span class="cx"> raise InvalidRequestError("Instance '%s' is not persisted" % repr(object)) </span><span class="lines">@@ -316,25 +337,28 @@ </span><span class="cx"> self._register_clean(object) </span><span class="cx"> </span><span class="cx"> def _register_new(self, obj): </span><del>- self._bind_to(obj) </del><ins>+ self._attach(obj) </ins><span class="cx"> self.uow.register_new(obj) </span><span class="cx"> def _register_dirty(self, obj): </span><del>- self._bind_to(obj) </del><ins>+ self._attach(obj) </ins><span class="cx"> self.uow.register_dirty(obj) </span><span class="cx"> def _register_clean(self, obj): </span><del>- self._bind_to(obj) </del><ins>+ self._attach(obj) </ins><span class="cx"> self.uow.register_clean(obj) </span><span class="cx"> def _register_deleted(self, obj): </span><del>- self._bind_to(obj) </del><ins>+ self._attach(obj) </ins><span class="cx"> self.uow.register_deleted(obj) </span><span class="cx"> </span><del>- def _bind_to(self, obj): - """given an object, binds it to this session. """ </del><ins>+ def _attach(self, obj): + """given an object, attaches it to this session. """ </ins><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><del>- # remove from old session. we do this gingerly since _sessions is a WeakValueDict - # and it might be affected by other threads </del><span class="cx"> if old is not None: </span><ins>+ raise InvalidRequestError("Object '%s' is already attached to session '%s'" % (repr(obj), old)) + + # auto-removal from the old session is disabled. but if we decide to + # turn it back on, do it as below: gingerly since _sessions is a WeakValueDict + # and it might be affected by other threads </ins><span class="cx"> try: </span><span class="cx"> sess = _sessions[old] </span><span class="cx"> except KeyError: </span><span class="lines">@@ -345,11 +369,18 @@ </span><span class="cx"> if key is not None: </span><span class="cx"> self.identity_map[key] = obj </span><span class="cx"> obj._sa_session_id = self.hash_key </span><del>- def _is_bound(self, obj): </del><ins>+ + def _unattach(self, obj): + if not self._is_attached(obj): #getattr(obj, '_sa_session_id', None) != self.hash_key: + raise InvalidRequestError("Object '%s' is not attached to this Session" % repr(obj)) + del obj._sa_session_id + + def _is_attached(self, obj): </ins><span class="cx"> return getattr(obj, '_sa_session_id', None) == self.hash_key </span><span class="cx"> def __contains__(self, obj): </span><del>- return self._is_bound(obj) and (obj in self.uow.new or self.uow.has_key(obj._instance_key)) - </del><ins>+ return self._is_attached(obj) and (obj in self.uow.new or self.uow.has_key(obj._instance_key)) + def __iter__(self): + return iter(self.uow.identity_map.values()) </ins><span class="cx"> def _get(self, key): </span><span class="cx"> return self.uow._get(key) </span><span class="cx"> def has_key(self, key): </span><span class="lines">@@ -392,37 +423,40 @@ </span><span class="cx"> # actual Session object directly to the object instance. </span><span class="cx"> _sessions = weakref.WeakValueDictionary() </span><span class="cx"> </span><del>-def get_session(obj=None, raiseerror=True): - """returns the Session corrseponding to the given object instance. By default, if the object is not bound - to any Session, then an error is raised (or None is returned if raiseerror=False). This behavior can be changed - using the "threadlocal" mod, which will add an additional step to return a Session that is bound to the current - thread.""" - if obj is not None: - # does it have a hash key ? - hashkey = getattr(obj, '_sa_session_id', None) - if hashkey is not None: - # ok, return that - try: - return _sessions[hashkey] - except KeyError: - if raiseerror: - raise InvalidRequestError("Session '%s' referenced by object '%s' no longer exists" % (hashkey, repr(obj))) - else: - return None - - return _default_session(obj=obj, raiseerror=raiseerror) </del><ins>+def current_session(obj=None): + if hasattr(obj.__class__, '__sessioncontext__'): + return obj.__class__.__sessioncontext__() + else: + return _default_session(obj=obj) + +# deprecated +get_session=current_session </ins><span class="cx"> </span><del>-def _default_session(obj=None, raiseerror=True): - if obj is None: - if raiseerror: - raise InvalidRequestError("Thread-local Sessions are disabled by default. Use 'import sqlalchemy.mods.threadlocal' to enable.") </del><ins>+def required_current_session(obj=None): + s = current_session(obj) + if s is None: + if obj is None: + raise InvalidRequestError("No global-level Session context is established. Use 'import sqlalchemy.mods.threadlocal' to establish a default thread-local context.") </ins><span class="cx"> else: </span><ins>+ raise InvalidRequestError("No Session context is established for class '%s', and no global-level Session context is established. Use 'import sqlalchemy.mods.threadlocal' to establish a default thread-local context." % (obj.__class__)) + return s + +def _default_session(obj=None): + return None +def register_default_session(callable_): + global _default_session + _default_session = callable_ + +def object_session(obj): + hashkey = getattr(obj, '_sa_session_id', None) + if hashkey is not None: + # ok, return that + try: + return _sessions[hashkey] + except KeyError: </ins><span class="cx"> return None </span><span class="cx"> else: </span><del>- if raiseerror: - raise InvalidRequestError("Object '%s' not bound to any Session" % (repr(obj))) - else: - return None - -unitofwork.get_session = get_session </del><ins>+ return None </ins><span class="cx"> </span><ins>+unitofwork.object_session = object_session + </ins></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormunitofworkpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/unitofwork.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -43,7 +43,7 @@ </span><span class="cx"> attributes.ListAttribute.__init__(self, obj, key, data=data, **kwargs) </span><span class="cx"> self.cascade = cascade </span><span class="cx"> def do_value_changed(self, obj, key, item, listval, isdelete): </span><del>- sess = get_session(obj, raiseerror=False) </del><ins>+ sess = object_session(obj) </ins><span class="cx"> if sess is not None: </span><span class="cx"> sess._register_dirty(obj) </span><span class="cx"> if self.cascade is not None: </span><span class="lines">@@ -62,7 +62,7 @@ </span><span class="cx"> self.cascade=cascade </span><span class="cx"> def do_value_changed(self, oldvalue, newvalue): </span><span class="cx"> obj = self.obj </span><del>- sess = get_session(obj, raiseerror=False) </del><ins>+ sess = object_session(obj) </ins><span class="cx"> if sess is not None: </span><span class="cx"> sess._register_dirty(obj) </span><span class="cx"> if self.cascade is not None: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormutilpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/util.py (1358 => 1359)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/util.py 2006-04-29 17:16:16 UTC (rev 1358) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/util.py 2006-04-29 18:41:13 UTC (rev 1359) </span><span class="lines">@@ -11,10 +11,10 @@ </span><span class="cx"> def __init__(self, arg=""): </span><span class="cx"> values = sets.Set([c.strip() for c in arg.split(',')]) </span><span class="cx"> self.delete_orphan = "delete-orphan" in values </span><del>- self.delete = "delete" in values or self.delete_orphan - self.save_update = "save-update" in values - self.merge = "merge" in values - self.expunge = "expunge" in values </del><ins>+ self.delete = "delete" in values or self.delete_orphan or "all" in values + self.save_update = "save-update" in values or "all" in values + self.merge = "merge" in values or "all" in values + self.expunge = "expunge" in values or "all" in values </ins><span class="cx"> def __contains__(self, item): </span><span class="cx"> return getattr(self, item.replace("-", "_"), False) </span><span class="cx"> </span><span class="cx">\ No newline at end of file </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 17:16:29
|
<!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>[1358] sqlalchemy/branches/schema/test: merged changes from trunk 1355-1357, re: types, unit test qualifiers</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1358</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 12:16:16 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>merged changes from trunk 1355-1357, re: types, unit test qualifiers</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasesmysqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemytypespy">sqlalchemy/branches/schema/lib/sqlalchemy/types.py</a></li> <li><a href="#sqlalchemybranchesschematestdefaultspy">sqlalchemy/branches/schema/test/defaults.py</a></li> <li><a href="#sqlalchemybranchesschematestinheritancepy">sqlalchemy/branches/schema/test/inheritance.py</a></li> <li><a href="#sqlalchemybranchesschematestobjectstorepy">sqlalchemy/branches/schema/test/objectstore.py</a></li> <li><a href="#sqlalchemybranchesschematestselectresultspy">sqlalchemy/branches/schema/test/selectresults.py</a></li> <li><a href="#sqlalchemybranchesschematesttestbasepy">sqlalchemy/branches/schema/test/testbase.py</a></li> <li><a href="#sqlalchemybranchesschematesttesttypespy">sqlalchemy/branches/schema/test/testtypes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/mysql.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -79,6 +79,11 @@ </span><span class="cx"> return "BINARY(%d)" % self.length </span><span class="cx"> else: </span><span class="cx"> return "BLOB" </span><ins>+ def convert_result_value(self, value, engine): + if value is None: + return None + else: + return buffer(value) </ins><span class="cx"> </span><span class="cx"> class MSBoolean(sqltypes.Boolean): </span><span class="cx"> def get_col_spec(self): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemytypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/types.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/types.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/lib/sqlalchemy/types.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -12,14 +12,13 @@ </span><span class="cx"> ] </span><span class="cx"> </span><span class="cx"> import sqlalchemy.util as util </span><ins>+import sqlalchemy.exceptions as exceptions </ins><span class="cx"> try: </span><span class="cx"> import cPickle as pickle </span><span class="cx"> except: </span><span class="cx"> import pickle </span><span class="cx"> </span><del>-class TypeEngine(object): - def __init__(self, *args, **kwargs): - pass </del><ins>+class AbstractType(object): </ins><span class="cx"> def _get_impl_dict(self): </span><span class="cx"> try: </span><span class="cx"> return self._impl_dict </span><span class="lines">@@ -27,6 +26,11 @@ </span><span class="cx"> self._impl_dict = {} </span><span class="cx"> return self._impl_dict </span><span class="cx"> impl_dict = property(_get_impl_dict) </span><ins>+ + +class TypeEngine(AbstractType): + def __init__(self, *args, **params): + pass </ins><span class="cx"> def engine_impl(self, engine): </span><span class="cx"> return self.dialect_impl(engine.dialect) </span><span class="cx"> def dialect_impl(self, dialect): </span><span class="lines">@@ -43,18 +47,42 @@ </span><span class="cx"> self._impl = impl </span><span class="cx"> impl = property(_get_impl, _set_impl) </span><span class="cx"> def get_col_spec(self): </span><ins>+ raise NotImplementedError() + def convert_bind_param(self, value, engine): + return value + def convert_result_value(self, value, engine): + return value + def adapt(self, cls): + return cls() + + +class TypeDecorator(AbstractType): + def __init__(self, *args, **kwargs): + if not hasattr(self.__class__, 'impl'): + raise exceptions.AssertionError("TypeDecorator implementations require a class-level variable 'impl' which refers to the class of type being decorated") + self.impl = self.__class__.impl(*args, **kwargs) + def engine_impl(self, engine): + return self.dialect_impl(engine.dialect) + def dialect_impl(self, dialect): + try: + return self.impl_dict[dialect] + except: + typedesc = dialect.type_descriptor(self.impl) + tt = self.copy() + if not isinstance(tt, self.__class__): + raise exceptions.AssertionError("Type object %s does not properly implement the copy() method, it must return an object of type %s" % (self, self.__class__)) + tt.impl = typedesc + self.impl_dict[dialect] = tt + return tt + def get_col_spec(self): </ins><span class="cx"> return self.impl.get_col_spec() </span><span class="cx"> def convert_bind_param(self, value, dialect): </span><span class="cx"> return self.impl.convert_bind_param(value, dialect) </span><span class="cx"> def convert_result_value(self, value, dialect): </span><span class="cx"> return self.impl.convert_result_value(value, dialect) </span><del>- def set_impl(self, impltype): - self.impl = impltype(**self.get_constructor_args()) - def get_constructor_args(self): - return {} - def adapt_args(self): - return self - </del><ins>+ def copy(self): + raise NotImplementedError() + </ins><span class="cx"> def to_instance(typeobj): </span><span class="cx"> if typeobj is None: </span><span class="cx"> return NULLTYPE </span><span class="lines">@@ -65,8 +93,7 @@ </span><span class="cx"> def adapt_type(typeobj, colspecs): </span><span class="cx"> if isinstance(typeobj, type): </span><span class="cx"> typeobj = typeobj() </span><del>- t2 = typeobj.adapt_args() - for t in t2.__class__.__mro__[0:-1]: </del><ins>+ for t in typeobj.__class__.__mro__[0:-1]: </ins><span class="cx"> try: </span><span class="cx"> impltype = colspecs[t] </span><span class="cx"> break </span><span class="lines">@@ -75,9 +102,7 @@ </span><span class="cx"> else: </span><span class="cx"> # couldnt adapt...raise exception ? </span><span class="cx"> return typeobj </span><del>- typeobj.set_impl(impltype) - typeobj.impl.impl = NULLTYPE - return typeobj </del><ins>+ return typeobj.adapt(impltype) </ins><span class="cx"> </span><span class="cx"> class NullTypeEngine(TypeEngine): </span><span class="cx"> def get_col_spec(self): </span><span class="lines">@@ -87,16 +112,17 @@ </span><span class="cx"> def convert_result_value(self, value, dialect): </span><span class="cx"> return value </span><span class="cx"> </span><del>-class TypeDecorator(object): - """TypeDecorator is deprecated""" - pass </del><span class="cx"> </span><del>- </del><span class="cx"> class String(TypeEngine): </span><ins>+ def __new__(cls, *args, **kwargs): + if cls is not String or len(args) > 0 or kwargs.has_key('length'): + return super(String, cls).__new__(cls, *args, **kwargs) + else: + return super(String, TEXT).__new__(TEXT, *args, **kwargs) </ins><span class="cx"> def __init__(self, length = None): </span><span class="cx"> self.length = length </span><del>- def get_constructor_args(self): - return {'length':self.length} </del><ins>+ def adapt(self, impltype): + return impltype(length=self.length) </ins><span class="cx"> def convert_bind_param(self, value, dialect): </span><span class="cx"> if not dialect.convert_unicode or value is None or not isinstance(value, unicode): </span><span class="cx"> return value </span><span class="lines">@@ -107,13 +133,9 @@ </span><span class="cx"> return value </span><span class="cx"> else: </span><span class="cx"> return value.decode(dialect.encoding) </span><del>- def adapt_args(self): - if self.length is None: - return TEXT() - else: - return self </del><span class="cx"> </span><del>-class Unicode(String): </del><ins>+class Unicode(TypeDecorator): + impl = String </ins><span class="cx"> def convert_bind_param(self, value, dialect): </span><span class="cx"> if value is not None and isinstance(value, unicode): </span><span class="cx"> return value.encode(dialect.encoding) </span><span class="lines">@@ -124,7 +146,9 @@ </span><span class="cx"> return value.decode(dialect.encoding) </span><span class="cx"> else: </span><span class="cx"> return value </span><del>- </del><ins>+ def copy(self): + return Unicode(self.impl.length) + </ins><span class="cx"> class Integer(TypeEngine): </span><span class="cx"> """integer datatype""" </span><span class="cx"> pass </span><span class="lines">@@ -138,49 +162,57 @@ </span><span class="cx"> def __init__(self, precision = 10, length = 2): </span><span class="cx"> self.precision = precision </span><span class="cx"> self.length = length </span><del>- def get_constructor_args(self): - return {'precision':self.precision, 'length':self.length} </del><ins>+ def adapt(self, impltype): + return impltype(precision=self.precision, length=self.length) </ins><span class="cx"> </span><span class="cx"> class Float(Numeric): </span><span class="cx"> def __init__(self, precision = 10): </span><span class="cx"> self.precision = precision </span><del>- def get_constructor_args(self): - return {'precision':self.precision} </del><ins>+ def adapt(self, impltype): + return impltype(precision=self.precision) </ins><span class="cx"> </span><span class="cx"> class DateTime(TypeEngine): </span><ins>+ """implements a type for datetime.datetime() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Date(TypeEngine): </span><ins>+ """implements a type for datetime.date() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Time(TypeEngine): </span><ins>+ """implements a type for datetime.time() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Binary(TypeEngine): </span><span class="cx"> def __init__(self, length=None): </span><span class="cx"> self.length = length </span><span class="cx"> def convert_bind_param(self, value, dialect): </span><del>- return dialect.dbapi().Binary(value) </del><ins>+ if value is not None: + return dialect.dbapi().Binary(value) + else: + return None </ins><span class="cx"> def convert_result_value(self, value, dialect): </span><span class="cx"> return value </span><del>- def get_constructor_args(self): - return {'length':self.length} </del><ins>+ def adapt(self, impltype): + return impltype(length=self.length) </ins><span class="cx"> </span><del>-class PickleType(Binary): - def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): - """allows the pickle protocol to be specified""" - self.protocol = protocol - def convert_result_value(self, value, dialect): - if value is None: - return None - buf = Binary.convert_result_value(self, value, dialect) - return pickle.loads(str(buf)) - def convert_bind_param(self, value, dialect): - if value is None: - return None - return Binary.convert_bind_param(self, pickle.dumps(value, self.protocol), dialect) - def get_constructor_args(self): - return {} </del><ins>+class PickleType(TypeDecorator): + impl = Binary + def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): + """allows the pickle protocol to be specified""" + self.protocol = protocol + super(PickleType, self).__init__() + def convert_result_value(self, value, dialect): + if value is None: + return None + buf = self.impl.convert_result_value(value, dialect) + return pickle.loads(str(buf)) + def convert_bind_param(self, value, dialect): + if value is None: + return None + return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), dialect) + def copy(self): + return PickleType(self.protocol) </ins><span class="cx"> </span><span class="cx"> class Boolean(TypeEngine): </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemybranchesschematestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/defaults.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/defaults.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/defaults.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -132,7 +132,8 @@ </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> cartitems.create() </span><del>- </del><ins>+ + @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def testsequence(self): </span><span class="cx"> cartitems.insert().execute(description='hi') </span><span class="cx"> cartitems.insert().execute(description='there') </span><span class="lines">@@ -141,6 +142,7 @@ </span><span class="cx"> cartitems.select().execute().fetchall() </span><span class="cx"> </span><span class="cx"> </span><ins>+ @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def teststandalone(self): </span><span class="cx"> s = Sequence("my_sequence", metadata=testbase.db) </span><span class="cx"> s.create() </span><span class="lines">@@ -150,6 +152,7 @@ </span><span class="cx"> finally: </span><span class="cx"> s.drop() </span><span class="cx"> </span><ins>+ @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def teststandalone2(self): </span><span class="cx"> x = cartitems.c.cart_id.sequence.execute() </span><span class="cx"> self.assert_(1 <= x <= 4) </span></span></pre></div> <a id="sqlalchemybranchesschematestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/inheritance.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/inheritance.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/inheritance.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -383,6 +383,21 @@ </span><span class="cx"> #contents.add_property('content_type', relation(content_types)) #adding this makes the inheritance stop working </span><span class="cx"> # shouldnt throw exception </span><span class="cx"> products = mapper(Product, product, inherits=contents) </span><ins>+ + def testbackref(self): + """this test is currently known to fail in the 0.1 series of SQLAlchemy, pending the resolution of [ticket:154]""" + class ContentType(object): pass + class Content(object): pass + class Product(Content): pass + + # this test fails currently + contents = mapper(Content, content) + products = mapper(Product, product, inherits=contents) + content_types = mapper(ContentType, content_type, properties={ + 'content':relation(contents, backref='contenttype') + }) + p = Product() + p.contenttype = ContentType() </ins><span class="cx"> </span><span class="cx"> class InheritTest6(testbase.AssertMixin): </span><span class="cx"> """tests eager load/lazy load of child items off inheritance mappers, tests that </span></span></pre></div> <a id="sqlalchemybranchesschematestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/objectstore.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/objectstore.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/objectstore.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -90,7 +90,8 @@ </span><span class="cx"> version_table.delete().execute() </span><span class="cx"> objectstore.clear() </span><span class="cx"> clear_mappers() </span><del>- </del><ins>+ + @testbase.unsupported('mysql') </ins><span class="cx"> def testbasic(self): </span><span class="cx"> s = Session() </span><span class="cx"> class Foo(object):pass </span><span class="lines">@@ -197,6 +198,8 @@ </span><span class="cx"> def setUp(self): </span><span class="cx"> objectstore.clear() </span><span class="cx"> clear_mappers() </span><ins>+ + @testbase.unsupported('sqlite') </ins><span class="cx"> def testprimarykey(self): </span><span class="cx"> class Entry(object): </span><span class="cx"> pass </span><span class="lines">@@ -496,7 +499,7 @@ </span><span class="cx"> usersaddresses = sql.join(users, addresses, users.c.user_id == addresses.c.user_id) </span><span class="cx"> print usersaddresses._get_col_by_original(users.c.user_id) </span><span class="cx"> print repr(usersaddresses._orig_cols) </span><del>- m = mapper(User, usersaddresses, primarytable = users, </del><ins>+ m = mapper(User, usersaddresses, </ins><span class="cx"> properties = dict( </span><span class="cx"> email = addresses.c.email_address, </span><span class="cx"> foo_id = [users.c.user_id, addresses.c.user_id], </span></span></pre></div> <a id="sqlalchemybranchesschematestselectresultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/selectresults.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/selectresults.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/selectresults.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -42,8 +42,14 @@ </span><span class="cx"> assert self.res.count() == 100 </span><span class="cx"> assert self.res.filter(foo.c.bar<30).min(foo.c.bar) == 0 </span><span class="cx"> assert self.res.filter(foo.c.bar<30).max(foo.c.bar) == 29 </span><ins>+ + @testbase.unsupported('mysql') + def test_aggregate_1(self): </ins><span class="cx"> # this one fails in mysql as the result comes back as a string </span><span class="cx"> assert self.res.filter(foo.c.bar<30).sum(foo.c.bar) == 435 </span><ins>+ + @testbase.unsupported('postgres', 'mysql') + def test_aggregate_2(self): </ins><span class="cx"> # this one fails with postgres, the floating point comparison fails </span><span class="cx"> assert self.res.filter(foo.c.bar<30).avg(foo.c.bar) == 14.5 </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschematesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/testbase.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/testbase.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/testbase.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -74,13 +74,44 @@ </span><span class="cx"> db = EngineAssert(db) </span><span class="cx"> metadata = sqlalchemy.BoundMetaData(db) </span><span class="cx"> </span><ins>+def unsupported(*dbs): + """a decorator that marks a test as unsupported by one or more database implementations""" + def decorate(func): + name = db.name + for d in dbs: + if d == name: + def lala(self): + echo_text("'" + func.__name__ + "' unsupported on DB implementation '" + name + "'") + lala.__name__ = func.__name__ + return lala + else: + return func + return decorate + +def supported(*dbs): + """a decorator that marks a test as supported by one or more database implementations""" + def decorate(func): + name = db.name + for d in dbs: + if d == name: + return func + else: + def lala(self): + echo_text("'" + func.__name__ + "' unsupported on DB implementation '" + name + "'") + lala.__name__ = func.__name__ + return lala + return decorate + +def echo_text(text): + print text + </ins><span class="cx"> class PersistTest(unittest.TestCase): </span><span class="cx"> """persist base class, provides default setUpAll, tearDownAll and echo functionality""" </span><span class="cx"> def __init__(self, *args, **params): </span><span class="cx"> unittest.TestCase.__init__(self, *args, **params) </span><span class="cx"> def echo(self, text): </span><span class="cx"> if echo: </span><del>- print text </del><ins>+ echo_text(text) </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> pass </span><span class="cx"> def tearDownAll(self): </span></span></pre></div> <a id="sqlalchemybranchesschematesttesttypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/testtypes.py (1357 => 1358)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/testtypes.py 2006-04-29 16:42:37 UTC (rev 1357) +++ sqlalchemy/branches/schema/test/testtypes.py 2006-04-29 17:16:16 UTC (rev 1358) </span><span class="lines">@@ -2,7 +2,8 @@ </span><span class="cx"> import string,datetime, re, sys </span><span class="cx"> from testbase import PersistTest, AssertMixin </span><span class="cx"> import testbase </span><del>- </del><ins>+import sqlalchemy.engine.url as url + </ins><span class="cx"> db = testbase.db </span><span class="cx"> </span><span class="cx"> class MyType(types.TypeEngine): </span><span class="lines">@@ -14,21 +15,48 @@ </span><span class="cx"> return value + "BIND_OUT" </span><span class="cx"> def adapt(self, typeobj): </span><span class="cx"> return typeobj() </span><del>- def adapt_args(self): - return self </del><span class="cx"> </span><del>-class MyDecoratedType(types.String): </del><ins>+class MyDecoratedType(types.TypeDecorator): + impl = String </ins><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> return "BIND_IN"+ value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value + "BIND_OUT" </span><del>- </del><ins>+ def copy(self): + return MyDecoratedType() + </ins><span class="cx"> class MyUnicodeType(types.Unicode): </span><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> return "UNI_BIND_IN"+ value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value + "UNI_BIND_OUT" </span><ins>+ def copy(self): + return MyUnicodeType(self.impl.length) </ins><span class="cx"> </span><ins>+class AdaptTest(PersistTest): + def testadapt(self): + e1 = url.URL('postgres').get_module().dialect() + e2 = url.URL('mysql').get_module().dialect() + e3 = url.URL('sqlite').get_module().dialect() + + type = String(40) + + t1 = type.dialect_impl(e1) + t2 = type.dialect_impl(e2) + t3 = type.dialect_impl(e3) + assert t1 != t2 + assert t2 != t3 + assert t3 != t1 + + def testdecorator(self): + t1 = Unicode(20) + t2 = Unicode() + assert isinstance(t1.impl, String) + assert not isinstance(t1.impl, TEXT) + assert (t1.impl.length == 20) + assert isinstance(t2.impl, TEXT) + assert t2.impl.length is None + </ins><span class="cx"> class OverrideTest(PersistTest): </span><span class="cx"> """tests user-defined types, including a full type as well as a TypeDecorator""" </span><span class="cx"> </span><span class="lines">@@ -132,7 +160,15 @@ </span><span class="cx"> self.assert_(isinstance(x['plain_data'], unicode) and x['plain_data'] == unicodedata) </span><span class="cx"> finally: </span><span class="cx"> db.engine.dialect.convert_unicode = prev_unicode </span><del>- </del><ins>+ +class Foo(object): + def __init__(self, moredata): + self.data = 'im data' + self.stuff = 'im stuff' + self.moredata = moredata + def __eq__(self, other): + return other.data == self.data and other.stuff == self.stuff and other.moredata==self.moredata + </ins><span class="cx"> class BinaryTest(AssertMixin): </span><span class="cx"> def setUpAll(self): </span><span class="cx"> global binary_table </span><span class="lines">@@ -140,20 +176,28 @@ </span><span class="cx"> Column('primary_id', Integer, primary_key=True), </span><span class="cx"> Column('data', Binary), </span><span class="cx"> Column('data_slice', Binary(100)), </span><del>- Column('misc', String(30))) </del><ins>+ Column('misc', String(30)), + Column('pickled', PickleType) + ) </ins><span class="cx"> binary_table.create() </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> binary_table.drop() </span><span class="cx"> def testbinary(self): </span><ins>+ testobj1 = Foo('im foo 1') + testobj2 = Foo('im foo 2') + </ins><span class="cx"> stream1 =self.get_module_stream('sqlalchemy.sql') </span><del>- stream2 =self.get_module_stream('sqlalchemy.engine') - binary_table.insert().execute(primary_id=1, misc='sql.pyc', data=stream1, data_slice=stream1[0:100]) - binary_table.insert().execute(primary_id=2, misc='engine.pyc', data=stream2, data_slice=stream2[0:99]) </del><ins>+ stream2 =self.get_module_stream('sqlalchemy.schema') + binary_table.insert().execute(primary_id=1, misc='sql.pyc', data=stream1, data_slice=stream1[0:100], pickled=testobj1) + binary_table.insert().execute(primary_id=2, misc='schema.pyc', data=stream2, data_slice=stream2[0:99], pickled=testobj2) </ins><span class="cx"> l = binary_table.select().execute().fetchall() </span><span class="cx"> print len(stream1), len(l[0]['data']), len(l[0]['data_slice']) </span><span class="cx"> self.assert_(list(stream1) == list(l[0]['data'])) </span><span class="cx"> self.assert_(list(stream1[0:100]) == list(l[0]['data_slice'])) </span><span class="cx"> self.assert_(list(stream2) == list(l[1]['data'])) </span><ins>+ self.assert_(testobj1 == l[0]['pickled']) + self.assert_(testobj2 == l[1]['pickled']) + </ins><span class="cx"> def get_module_stream(self, name): </span><span class="cx"> mod = __import__(name) </span><span class="cx"> for token in name.split('.')[1:]: </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 16:42:47
|
<!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>[1357] sqlalchemy/trunk/test: added 'supports', 'unsupports' decorators to unittests so that they can all pass on all DBs</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1357</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 11:42:37 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>added 'supports', 'unsupports' decorators to unittests so that they can all pass on all DBs</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktestdefaultspy">sqlalchemy/trunk/test/defaults.py</a></li> <li><a href="#sqlalchemytrunktestinheritancepy">sqlalchemy/trunk/test/inheritance.py</a></li> <li><a href="#sqlalchemytrunktestobjectstorepy">sqlalchemy/trunk/test/objectstore.py</a></li> <li><a href="#sqlalchemytrunktestselectresultspy">sqlalchemy/trunk/test/selectresults.py</a></li> <li><a href="#sqlalchemytrunktesttestbasepy">sqlalchemy/trunk/test/testbase.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/defaults.py (1356 => 1357)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/defaults.py 2006-04-29 16:12:02 UTC (rev 1356) +++ sqlalchemy/trunk/test/defaults.py 2006-04-29 16:42:37 UTC (rev 1357) </span><span class="lines">@@ -131,7 +131,8 @@ </span><span class="cx"> ) </span><span class="cx"> </span><span class="cx"> cartitems.create() </span><del>- </del><ins>+ + @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def testsequence(self): </span><span class="cx"> cartitems.insert().execute(description='hi') </span><span class="cx"> cartitems.insert().execute(description='there') </span><span class="lines">@@ -140,6 +141,7 @@ </span><span class="cx"> cartitems.select().execute().fetchall() </span><span class="cx"> </span><span class="cx"> </span><ins>+ @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def teststandalone(self): </span><span class="cx"> s = Sequence("my_sequence", engine=db) </span><span class="cx"> s.create() </span><span class="lines">@@ -149,6 +151,7 @@ </span><span class="cx"> finally: </span><span class="cx"> s.drop() </span><span class="cx"> </span><ins>+ @testbase.supported('postgres', 'oracle') </ins><span class="cx"> def teststandalone2(self): </span><span class="cx"> x = cartitems.c.cart_id.sequence.execute() </span><span class="cx"> self.assert_(1 <= x <= 4) </span></span></pre></div> <a id="sqlalchemytrunktestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/inheritance.py (1356 => 1357)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/inheritance.py 2006-04-29 16:12:02 UTC (rev 1356) +++ sqlalchemy/trunk/test/inheritance.py 2006-04-29 16:42:37 UTC (rev 1357) </span><span class="lines">@@ -384,7 +384,9 @@ </span><span class="cx"> # shouldnt throw exception </span><span class="cx"> products = mapper(Product, product, inherits=contents) </span><span class="cx"> </span><ins>+ </ins><span class="cx"> def testbackref(self): </span><ins>+ """this test is currently known to fail in the 0.1 series of SQLAlchemy, pending the resolution of [ticket:154]""" </ins><span class="cx"> class ContentType(object): pass </span><span class="cx"> class Content(object): pass </span><span class="cx"> class Product(Content): pass </span></span></pre></div> <a id="sqlalchemytrunktestobjectstorepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/objectstore.py (1356 => 1357)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/objectstore.py 2006-04-29 16:12:02 UTC (rev 1356) +++ sqlalchemy/trunk/test/objectstore.py 2006-04-29 16:42:37 UTC (rev 1357) </span><span class="lines">@@ -143,7 +143,8 @@ </span><span class="cx"> trans.commit() </span><span class="cx"> self.assert_(name_of(7) != name1, msg="user_name should not be %s" % name1) </span><span class="cx"> self.assert_(name_of(8) != name2, msg="user_name should not be %s" % name2) </span><del>- </del><ins>+ + @testbase.unsupported('sqlite') </ins><span class="cx"> def test_true_nested(self): </span><span class="cx"> """tests creating a new Session inside a database transaction, in </span><span class="cx"> conjunction with an engine-level nested transaction, which uses </span><span class="lines">@@ -185,7 +186,8 @@ </span><span class="cx"> version_table.delete().execute() </span><span class="cx"> objectstore.clear() </span><span class="cx"> clear_mappers() </span><del>- </del><ins>+ + @testbase.unsupported('mysql') </ins><span class="cx"> def testbasic(self): </span><span class="cx"> class Foo(object):pass </span><span class="cx"> assign_mapper(Foo, version_table, version_id_col=version_table.c.version_id) </span><span class="lines">@@ -287,6 +289,8 @@ </span><span class="cx"> def setUp(self): </span><span class="cx"> objectstore.clear() </span><span class="cx"> clear_mappers() </span><ins>+ + @testbase.unsupported('sqlite') </ins><span class="cx"> def testprimarykey(self): </span><span class="cx"> class Entry(object): </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemytrunktestselectresultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/selectresults.py (1356 => 1357)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/selectresults.py 2006-04-29 16:12:02 UTC (rev 1356) +++ sqlalchemy/trunk/test/selectresults.py 2006-04-29 16:42:37 UTC (rev 1357) </span><span class="lines">@@ -42,8 +42,14 @@ </span><span class="cx"> assert self.res.count() == 100 </span><span class="cx"> assert self.res.filter(foo.c.bar<30).min(foo.c.bar) == 0 </span><span class="cx"> assert self.res.filter(foo.c.bar<30).max(foo.c.bar) == 29 </span><ins>+ + @testbase.unsupported('mysql') + def test_aggregate_1(self): </ins><span class="cx"> # this one fails in mysql as the result comes back as a string </span><span class="cx"> assert self.res.filter(foo.c.bar<30).sum(foo.c.bar) == 435 </span><ins>+ + @testbase.unsupported('postgres', 'mysql') + def test_aggregate_2(self): </ins><span class="cx"> # this one fails with postgres, the floating point comparison fails </span><span class="cx"> assert self.res.filter(foo.c.bar<30).avg(foo.c.bar) == 14.5 </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktesttestbasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testbase.py (1356 => 1357)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testbase.py 2006-04-29 16:12:02 UTC (rev 1356) +++ sqlalchemy/trunk/test/testbase.py 2006-04-29 16:42:37 UTC (rev 1357) </span><span class="lines">@@ -59,13 +59,44 @@ </span><span class="cx"> db = engine.create_engine(db_uri, echo=echo, default_ordering=True, **opts) </span><span class="cx"> db = EngineAssert(db) </span><span class="cx"> </span><ins>+def unsupported(*dbs): + """a decorator that marks a test as unsupported by one or more database implementations""" + def decorate(func): + name = db.name + for d in dbs: + if d == name: + def lala(self): + echo_text("'" + func.__name__ + "' unsupported on DB implementation '" + name + "'") + lala.__name__ = func.__name__ + return lala + else: + return func + return decorate + +def supported(*dbs): + """a decorator that marks a test as supported by one or more database implementations""" + def decorate(func): + name = db.name + for d in dbs: + if d == name: + return func + else: + def lala(self): + echo_text("'" + func.__name__ + "' unsupported on DB implementation '" + name + "'") + lala.__name__ = func.__name__ + return lala + return decorate + +def echo_text(text): + print text + </ins><span class="cx"> class PersistTest(unittest.TestCase): </span><span class="cx"> """persist base class, provides default setUpAll, tearDownAll and echo functionality""" </span><span class="cx"> def __init__(self, *args, **params): </span><span class="cx"> unittest.TestCase.__init__(self, *args, **params) </span><span class="cx"> def echo(self, text): </span><span class="cx"> if echo: </span><del>- print text </del><ins>+ echo_text(text) </ins><span class="cx"> def setUpAll(self): </span><span class="cx"> pass </span><span class="cx"> def tearDownAll(self): </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 16:12: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>[1356] sqlalchemy/trunk/test: more work on types.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1356</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-29 11:12:02 -0500 (Sat, 29 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>more work on types. this is the simplest implementation which is a little more manual</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemytypespy">sqlalchemy/trunk/lib/sqlalchemy/types.py</a></li> <li><a href="#sqlalchemytrunktesttesttypespy">sqlalchemy/trunk/test/testtypes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemytypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/types.py (1355 => 1356)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/types.py 2006-04-29 01:05:13 UTC (rev 1355) +++ sqlalchemy/trunk/lib/sqlalchemy/types.py 2006-04-29 16:12:02 UTC (rev 1356) </span><span class="lines">@@ -12,6 +12,7 @@ </span><span class="cx"> ] </span><span class="cx"> </span><span class="cx"> import sqlalchemy.util as util </span><ins>+import sqlalchemy.exceptions as exceptions </ins><span class="cx"> try: </span><span class="cx"> import cPickle as pickle </span><span class="cx"> except: </span><span class="lines">@@ -25,11 +26,7 @@ </span><span class="cx"> self._impl_dict = {} </span><span class="cx"> return self._impl_dict </span><span class="cx"> impl_dict = property(_get_impl_dict) </span><del>- def get_constructor_args(self): - return {} - def adapt_args(self): - return self - </del><ins>+ </ins><span class="cx"> class TypeEngine(AbstractType): </span><span class="cx"> def __init__(self, *args, **params): </span><span class="cx"> pass </span><span class="lines">@@ -44,16 +41,22 @@ </span><span class="cx"> return value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value </span><ins>+ def adapt(self, cls): + return cls() </ins><span class="cx"> </span><ins>+AbstractType.impl = TypeEngine + </ins><span class="cx"> class TypeDecorator(AbstractType): </span><del>- def __init__(self, *args, **params): - pass </del><ins>+ def __init__(self, *args, **kwargs): + self.impl = self.__class__.impl(*args, **kwargs) </ins><span class="cx"> def engine_impl(self, engine): </span><span class="cx"> try: </span><span class="cx"> return self.impl_dict[engine] </span><span class="cx"> except: </span><span class="cx"> typedesc = engine.type_descriptor(self.impl) </span><del>- tt = self.__class__(**self.get_constructor_args()) </del><ins>+ tt = self.copy() + if not isinstance(tt, self.__class__): + raise exceptions.AssertionError("Type object %s does not properly implement the copy() method, it must return an object of type %s" % (self, self.__class__)) </ins><span class="cx"> tt.impl = typedesc </span><span class="cx"> self.impl_dict[engine] = tt </span><span class="cx"> return tt </span><span class="lines">@@ -63,6 +66,8 @@ </span><span class="cx"> return self.impl.convert_bind_param(value, engine) </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return self.impl.convert_result_value(value, engine) </span><ins>+ def copy(self): + raise NotImplementedError() </ins><span class="cx"> </span><span class="cx"> def to_instance(typeobj): </span><span class="cx"> if typeobj is None: </span><span class="lines">@@ -74,8 +79,7 @@ </span><span class="cx"> def adapt_type(typeobj, colspecs): </span><span class="cx"> if isinstance(typeobj, type): </span><span class="cx"> typeobj = typeobj() </span><del>- t2 = typeobj.adapt_args() - for t in t2.__class__.__mro__[0:-1]: </del><ins>+ for t in typeobj.__class__.__mro__[0:-1]: </ins><span class="cx"> try: </span><span class="cx"> impltype = colspecs[t] </span><span class="cx"> break </span><span class="lines">@@ -84,7 +88,7 @@ </span><span class="cx"> else: </span><span class="cx"> # couldnt adapt...raise exception ? </span><span class="cx"> return typeobj </span><del>- return impltype(**t2.get_constructor_args()) </del><ins>+ return typeobj.adapt(impltype) </ins><span class="cx"> </span><span class="cx"> class NullTypeEngine(TypeEngine): </span><span class="cx"> def get_col_spec(self): </span><span class="lines">@@ -96,10 +100,15 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> class String(TypeEngine): </span><ins>+ def __new__(cls, *args, **kwargs): + if cls is not String or len(args) > 0 or kwargs.has_key('length'): + return super(String, cls).__new__(cls, *args, **kwargs) + else: + return super(String, TEXT).__new__(TEXT, *args, **kwargs) </ins><span class="cx"> def __init__(self, length = None): </span><span class="cx"> self.length = length </span><del>- def get_constructor_args(self): - return {'length':self.length} </del><ins>+ def adapt(self, impltype): + return impltype(length=self.length) </ins><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> if not engine.convert_unicode or value is None or not isinstance(value, unicode): </span><span class="cx"> return value </span><span class="lines">@@ -110,11 +119,6 @@ </span><span class="cx"> return value </span><span class="cx"> else: </span><span class="cx"> return value.decode(engine.encoding) </span><del>- def adapt_args(self): - if self.length is None: - return TEXT() - else: - return self </del><span class="cx"> </span><span class="cx"> class Unicode(TypeDecorator): </span><span class="cx"> impl = String </span><span class="lines">@@ -128,7 +132,9 @@ </span><span class="cx"> return value.decode(engine.encoding) </span><span class="cx"> else: </span><span class="cx"> return value </span><del>- </del><ins>+ def copy(self): + return Unicode(self.impl.length) + </ins><span class="cx"> class Integer(TypeEngine): </span><span class="cx"> """integer datatype""" </span><span class="cx"> pass </span><span class="lines">@@ -142,22 +148,25 @@ </span><span class="cx"> def __init__(self, precision = 10, length = 2): </span><span class="cx"> self.precision = precision </span><span class="cx"> self.length = length </span><del>- def get_constructor_args(self): - return {'precision':self.precision, 'length':self.length} </del><ins>+ def adapt(self, impltype): + return impltype(precision=self.precision, length=self.length) </ins><span class="cx"> </span><span class="cx"> class Float(Numeric): </span><span class="cx"> def __init__(self, precision = 10): </span><span class="cx"> self.precision = precision </span><del>- def get_constructor_args(self): - return {'precision':self.precision} </del><ins>+ def adapt(self, impltype): + return impltype(precision=self.precision) </ins><span class="cx"> </span><span class="cx"> class DateTime(TypeEngine): </span><ins>+ """implements a type for datetime.datetime() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Date(TypeEngine): </span><ins>+ """implements a type for datetime.date() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Time(TypeEngine): </span><ins>+ """implements a type for datetime.time() objects""" </ins><span class="cx"> pass </span><span class="cx"> </span><span class="cx"> class Binary(TypeEngine): </span><span class="lines">@@ -167,25 +176,26 @@ </span><span class="cx"> return engine.dbapi().Binary(value) </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value </span><del>- def get_constructor_args(self): - return {'length':self.length} </del><ins>+ def adap(self, impltype): + return impltype(length=self.length) </ins><span class="cx"> </span><span class="cx"> class PickleType(TypeDecorator): </span><del>- def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): - """allows the pickle protocol to be specified""" - self.protocol = protocol - self.impl = Binary() - def convert_result_value(self, value, engine): - if value is None: - return None - buf = self.impl.convert_result_value(value, engine) - return pickle.loads(str(buf)) - def convert_bind_param(self, value, engine): - if value is None: - return None - return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), engine) - def get_constructor_args(self): - return {} </del><ins>+ impl = Binary + def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): + """allows the pickle protocol to be specified""" + self.protocol = protocol + super(PickleType, self).__init__() + def convert_result_value(self, value, engine): + if value is None: + return None + buf = self.impl.convert_result_value(value, engine) + return pickle.loads(str(buf)) + def convert_bind_param(self, value, engine): + if value is None: + return None + return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), engine) + def copy(self): + return PickleType(self.protocol) </ins><span class="cx"> </span><span class="cx"> class Boolean(TypeEngine): </span><span class="cx"> pass </span></span></pre></div> <a id="sqlalchemytrunktesttesttypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testtypes.py (1355 => 1356)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testtypes.py 2006-04-29 01:05:13 UTC (rev 1355) +++ sqlalchemy/trunk/test/testtypes.py 2006-04-29 16:12:02 UTC (rev 1356) </span><span class="lines">@@ -14,8 +14,6 @@ </span><span class="cx"> return value + "BIND_OUT" </span><span class="cx"> def adapt(self, typeobj): </span><span class="cx"> return typeobj() </span><del>- def adapt_args(self): - return self </del><span class="cx"> </span><span class="cx"> class MyDecoratedType(types.TypeDecorator): </span><span class="cx"> impl = String </span><span class="lines">@@ -23,12 +21,16 @@ </span><span class="cx"> return "BIND_IN"+ value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value + "BIND_OUT" </span><del>- </del><ins>+ def copy(self): + return MyDecoratedType() + </ins><span class="cx"> class MyUnicodeType(types.Unicode): </span><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> return "UNI_BIND_IN"+ value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value + "UNI_BIND_OUT" </span><ins>+ def copy(self): + return MyUnicodeType(self.impl.length) </ins><span class="cx"> </span><span class="cx"> class AdaptTest(PersistTest): </span><span class="cx"> def testadapt(self): </span><span class="lines">@@ -44,6 +46,15 @@ </span><span class="cx"> assert t1 != t2 </span><span class="cx"> assert t2 != t3 </span><span class="cx"> assert t3 != t1 </span><ins>+ + def testdecorator(self): + t1 = Unicode(20) + t2 = Unicode() + assert isinstance(t1.impl, String) + assert not isinstance(t1.impl, TEXT) + assert (t1.impl.length == 20) + assert isinstance(t2.impl, TEXT) + assert t2.impl.length is None </ins><span class="cx"> </span><span class="cx"> class OverrideTest(PersistTest): </span><span class="cx"> """tests user-defined types, including a full type as well as a TypeDecorator""" </span></span></pre> </div> </div> </body> </html> |
<!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>[1355] sqlalchemy/trunk/test: *another* big types change....the old way was still wrong...this way is better (still need to go through it again since i am apparently type-impaired....)</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1355</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 20:05:13 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>*another* big types change....the old way was still wrong...this way is better (still need to go through it again since i am apparently type-impaired....)</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemydatabasesmysqlpy">sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemytypespy">sqlalchemy/trunk/lib/sqlalchemy/types.py</a></li> <li><a href="#sqlalchemytrunktesttesttypespy">sqlalchemy/trunk/test/testtypes.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemydatabasesmysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py (1354 => 1355)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-04-29 00:08:07 UTC (rev 1354) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/mysql.py 2006-04-29 01:05:13 UTC (rev 1355) </span><span class="lines">@@ -79,6 +79,11 @@ </span><span class="cx"> return "BINARY(%d)" % self.length </span><span class="cx"> else: </span><span class="cx"> return "BLOB" </span><ins>+ def convert_result_value(self, value, engine): + if value is None: + return None + else: + return buffer(value) </ins><span class="cx"> </span><span class="cx"> class MSBoolean(sqltypes.Boolean): </span><span class="cx"> def get_col_spec(self): </span><span class="lines">@@ -142,7 +147,6 @@ </span><span class="cx"> </span><span class="cx"> def type_descriptor(self, typeobj): </span><span class="cx"> return sqltypes.adapt_type(typeobj, colspecs) </span><del>- </del><span class="cx"> def last_inserted_ids(self): </span><span class="cx"> return self.context.last_inserted_ids </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemytypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/types.py (1354 => 1355)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/types.py 2006-04-29 00:08:07 UTC (rev 1354) +++ sqlalchemy/trunk/lib/sqlalchemy/types.py 2006-04-29 01:05:13 UTC (rev 1355) </span><span class="lines">@@ -17,9 +17,7 @@ </span><span class="cx"> except: </span><span class="cx"> import pickle </span><span class="cx"> </span><del>-class TypeEngine(object): - def __init__(self, *args, **kwargs): - pass </del><ins>+class AbstractType(object): </ins><span class="cx"> def _get_impl_dict(self): </span><span class="cx"> try: </span><span class="cx"> return self._impl_dict </span><span class="lines">@@ -27,32 +25,45 @@ </span><span class="cx"> self._impl_dict = {} </span><span class="cx"> return self._impl_dict </span><span class="cx"> impl_dict = property(_get_impl_dict) </span><ins>+ def get_constructor_args(self): + return {} + def adapt_args(self): + return self + +class TypeEngine(AbstractType): + def __init__(self, *args, **params): + pass </ins><span class="cx"> def engine_impl(self, engine): </span><span class="cx"> try: </span><span class="cx"> return self.impl_dict[engine] </span><span class="cx"> except: </span><span class="cx"> return self.impl_dict.setdefault(engine, engine.type_descriptor(self)) </span><del>- def _get_impl(self): - if hasattr(self, '_impl'): - return self._impl - else: - return NULLTYPE - def _set_impl(self, impl): - self._impl = impl - impl = property(_get_impl, _set_impl) </del><span class="cx"> def get_col_spec(self): </span><ins>+ raise NotImplementedError() + def convert_bind_param(self, value, engine): + return value + def convert_result_value(self, value, engine): + return value + +class TypeDecorator(AbstractType): + def __init__(self, *args, **params): + pass + def engine_impl(self, engine): + try: + return self.impl_dict[engine] + except: + typedesc = engine.type_descriptor(self.impl) + tt = self.__class__(**self.get_constructor_args()) + tt.impl = typedesc + self.impl_dict[engine] = tt + return tt + def get_col_spec(self): </ins><span class="cx"> return self.impl.get_col_spec() </span><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> return self.impl.convert_bind_param(value, engine) </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return self.impl.convert_result_value(value, engine) </span><del>- def set_impl(self, impltype): - self.impl = impltype(**self.get_constructor_args()) - def get_constructor_args(self): - return {} - def adapt_args(self): - return self - </del><ins>+ </ins><span class="cx"> def to_instance(typeobj): </span><span class="cx"> if typeobj is None: </span><span class="cx"> return NULLTYPE </span><span class="lines">@@ -73,9 +84,7 @@ </span><span class="cx"> else: </span><span class="cx"> # couldnt adapt...raise exception ? </span><span class="cx"> return typeobj </span><del>- typeobj.set_impl(impltype) - typeobj.impl.impl = NULLTYPE - return typeobj </del><ins>+ return impltype(**t2.get_constructor_args()) </ins><span class="cx"> </span><span class="cx"> class NullTypeEngine(TypeEngine): </span><span class="cx"> def get_col_spec(self): </span><span class="lines">@@ -85,11 +94,7 @@ </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value </span><span class="cx"> </span><del>-class TypeDecorator(object): - """TypeDecorator is deprecated""" - pass </del><span class="cx"> </span><del>- </del><span class="cx"> class String(TypeEngine): </span><span class="cx"> def __init__(self, length = None): </span><span class="cx"> self.length = length </span><span class="lines">@@ -111,7 +116,8 @@ </span><span class="cx"> else: </span><span class="cx"> return self </span><span class="cx"> </span><del>-class Unicode(String): </del><ins>+class Unicode(TypeDecorator): + impl = String </ins><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> if value is not None and isinstance(value, unicode): </span><span class="cx"> return value.encode(engine.encoding) </span><span class="lines">@@ -164,19 +170,20 @@ </span><span class="cx"> def get_constructor_args(self): </span><span class="cx"> return {'length':self.length} </span><span class="cx"> </span><del>-class PickleType(Binary): </del><ins>+class PickleType(TypeDecorator): </ins><span class="cx"> def __init__(self, protocol=pickle.HIGHEST_PROTOCOL): </span><span class="cx"> """allows the pickle protocol to be specified""" </span><span class="cx"> self.protocol = protocol </span><ins>+ self.impl = Binary() </ins><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> if value is None: </span><span class="cx"> return None </span><del>- buf = Binary.convert_result_value(self, value, engine) </del><ins>+ buf = self.impl.convert_result_value(value, engine) </ins><span class="cx"> return pickle.loads(str(buf)) </span><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> if value is None: </span><span class="cx"> return None </span><del>- return Binary.convert_bind_param(self, pickle.dumps(value, self.protocol), engine) </del><ins>+ return self.impl.convert_bind_param(pickle.dumps(value, self.protocol), engine) </ins><span class="cx"> def get_constructor_args(self): </span><span class="cx"> return {} </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemytrunktesttesttypespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/testtypes.py (1354 => 1355)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/testtypes.py 2006-04-29 00:08:07 UTC (rev 1354) +++ sqlalchemy/trunk/test/testtypes.py 2006-04-29 01:05:13 UTC (rev 1355) </span><span class="lines">@@ -17,7 +17,8 @@ </span><span class="cx"> def adapt_args(self): </span><span class="cx"> return self </span><span class="cx"> </span><del>-class MyDecoratedType(types.String): </del><ins>+class MyDecoratedType(types.TypeDecorator): + impl = String </ins><span class="cx"> def convert_bind_param(self, value, engine): </span><span class="cx"> return "BIND_IN"+ value </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="lines">@@ -29,6 +30,21 @@ </span><span class="cx"> def convert_result_value(self, value, engine): </span><span class="cx"> return value + "UNI_BIND_OUT" </span><span class="cx"> </span><ins>+class AdaptTest(PersistTest): + def testadapt(self): + e1 = create_engine('postgres://') + e2 = create_engine('sqlite://') + e3 = create_engine('mysql://') + + type = String(40) + + t1 = type.engine_impl(e1) + t2 = type.engine_impl(e2) + t3 = type.engine_impl(e3) + assert t1 != t2 + assert t2 != t3 + assert t3 != t1 + </ins><span class="cx"> class OverrideTest(PersistTest): </span><span class="cx"> """tests user-defined types, including a full type as well as a TypeDecorator""" </span><span class="cx"> </span><span class="lines">@@ -132,6 +148,15 @@ </span><span class="cx"> self.assert_(isinstance(x['plain_data'], unicode) and x['plain_data'] == unicodedata) </span><span class="cx"> finally: </span><span class="cx"> db.engine.convert_unicode = prev_unicode </span><ins>+ + +class Foo(object): + def __init__(self, moredata): + self.data = 'im data' + self.stuff = 'im stuff' + self.moredata = moredata + def __eq__(self, other): + return other.data == self.data and other.stuff == self.stuff and other.moredata==self.moredata </ins><span class="cx"> </span><span class="cx"> class BinaryTest(AssertMixin): </span><span class="cx"> def setUpAll(self): </span><span class="lines">@@ -140,20 +165,29 @@ </span><span class="cx"> Column('primary_id', Integer, primary_key=True), </span><span class="cx"> Column('data', Binary), </span><span class="cx"> Column('data_slice', Binary(100)), </span><del>- Column('misc', String(30))) </del><ins>+ Column('misc', String(30)), + Column('pickled', PickleType)) </ins><span class="cx"> binary_table.create() </span><span class="cx"> def tearDownAll(self): </span><span class="cx"> binary_table.drop() </span><span class="cx"> def testbinary(self): </span><ins>+ testobj1 = Foo('im foo 1') + testobj2 = Foo('im foo 2') + </ins><span class="cx"> stream1 =self.get_module_stream('sqlalchemy.sql') </span><span class="cx"> stream2 =self.get_module_stream('sqlalchemy.engine') </span><del>- binary_table.insert().execute(primary_id=1, misc='sql.pyc', data=stream1, data_slice=stream1[0:100]) - binary_table.insert().execute(primary_id=2, misc='engine.pyc', data=stream2, data_slice=stream2[0:99]) </del><ins>+ binary_table.insert().execute(primary_id=1, misc='sql.pyc', data=stream1, data_slice=stream1[0:100], pickled=testobj1) + binary_table.insert().execute(primary_id=2, misc='engine.pyc', data=stream2, data_slice=stream2[0:99], pickled=testobj2) </ins><span class="cx"> l = binary_table.select().execute().fetchall() </span><ins>+ print type(l[0]['data']) + return </ins><span class="cx"> print len(stream1), len(l[0]['data']), len(l[0]['data_slice']) </span><span class="cx"> self.assert_(list(stream1) == list(l[0]['data'])) </span><span class="cx"> self.assert_(list(stream1[0:100]) == list(l[0]['data_slice'])) </span><span class="cx"> self.assert_(list(stream2) == list(l[1]['data'])) </span><ins>+ self.assert_(testobj1 == l[0]['pickled']) + self.assert_(testobj2 == l[1]['pickled']) + </ins><span class="cx"> def get_module_stream(self, name): </span><span class="cx"> mod = __import__(name) </span><span class="cx"> for token in name.split('.')[1:]: </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-29 00:08:20
|
<!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>[1354] sqlalchemy/branches/schema/test: merged [changeset:1353] fixes</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1354</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 19:08:07 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>merged [changeset:1353] fixes fixed some stuff related to connection scoping when running sequences/defaults added 'metadata' argument to DefaultGenerator</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyansisqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemydatabasespostgrespy">sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyenginebasepy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyschemapy">sqlalchemy/branches/schema/lib/sqlalchemy/schema.py</a></li> <li><a href="#sqlalchemybranchesschematestdefaultspy">sqlalchemy/branches/schema/test/defaults.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py (1353 => 1354)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py 2006-04-28 23:31:59 UTC (rev 1353) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py 2006-04-29 00:08:07 UTC (rev 1354) </span><span class="lines">@@ -138,7 +138,6 @@ </span><span class="cx"> continue </span><span class="cx"> d.set_parameter(b.key, value, b) </span><span class="cx"> </span><del>- #print "FROM", params, "TO", d </del><span class="cx"> return d </span><span class="cx"> </span><span class="cx"> def get_named_params(self, parameters): </span><span class="lines">@@ -426,26 +425,26 @@ </span><span class="cx"> " ON " + self.get_str(join.onclause)) </span><span class="cx"> self.strings[join] = self.froms[join] </span><span class="cx"> </span><del>- def visit_insert_column_default(self, column, default): </del><ins>+ def visit_insert_column_default(self, column, default, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><span class="cx"> contains a ColumnDefault object. adds a blank 'placeholder' parameter so the </span><span class="cx"> Insert gets compiled with this column's name in its column and VALUES clauses.""" </span><del>- self.parameters.setdefault(column.key, None) </del><ins>+ parameters.setdefault(column.key, None) </ins><span class="cx"> </span><del>- def visit_update_column_default(self, column, default): </del><ins>+ def visit_update_column_default(self, column, default, parameters): </ins><span class="cx"> """called when visiting an Update statement, for each column in the table that </span><span class="cx"> contains a ColumnDefault object as an onupdate. adds a blank 'placeholder' parameter so the </span><span class="cx"> Update gets compiled with this column's name as one of its SET clauses.""" </span><del>- self.parameters.setdefault(column.key, None) </del><ins>+ parameters.setdefault(column.key, None) </ins><span class="cx"> </span><del>- def visit_insert_sequence(self, column, sequence): </del><ins>+ def visit_insert_sequence(self, column, sequence, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><span class="cx"> contains a Sequence object. Overridden by compilers that support sequences to place </span><span class="cx"> a blank 'placeholder' parameter, so the Insert gets compiled with this column's </span><span class="cx"> name in its column and VALUES clauses.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def visit_insert_column(self, column): </del><ins>+ def visit_insert_column(self, column, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><span class="cx"> that is a NULL insert into the table. Overridden by compilers who disallow </span><span class="cx"> NULL columns being set in an Insert where there is a default value on the column </span><span class="lines">@@ -455,25 +454,27 @@ </span><span class="cx"> def visit_insert(self, insert_stmt): </span><span class="cx"> # scan the table's columns for defaults that have to be pre-set for an INSERT </span><span class="cx"> # add these columns to the parameter list via visit_insert_XXX methods </span><ins>+ default_params = {} </ins><span class="cx"> class DefaultVisitor(schema.SchemaVisitor): </span><span class="cx"> def visit_column(s, c): </span><del>- self.visit_insert_column(c) </del><ins>+ self.visit_insert_column(c, default_params) </ins><span class="cx"> def visit_column_default(s, cd): </span><del>- self.visit_insert_column_default(c, cd) </del><ins>+ self.visit_insert_column_default(c, cd, default_params) </ins><span class="cx"> def visit_sequence(s, seq): </span><del>- self.visit_insert_sequence(c, seq) </del><ins>+ self.visit_insert_sequence(c, seq, default_params) </ins><span class="cx"> vis = DefaultVisitor() </span><span class="cx"> for c in insert_stmt.table.c: </span><span class="cx"> if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): </span><span class="cx"> c.accept_schema_visitor(vis) </span><span class="cx"> </span><span class="cx"> self.isinsert = True </span><del>- colparams = self._get_colparams(insert_stmt) </del><ins>+ colparams = self._get_colparams(insert_stmt, default_params) </ins><span class="cx"> </span><span class="cx"> def create_param(p): </span><span class="cx"> if isinstance(p, sql.BindParamClause): </span><span class="cx"> self.binds[p.key] = p </span><del>- self.binds[p.shortname] = p </del><ins>+ if p.shortname is not None: + self.binds[p.shortname] = p </ins><span class="cx"> return self.bindparam_string(p.key) </span><span class="cx"> else: </span><span class="cx"> p.accept_visitor(self) </span><span class="lines">@@ -484,22 +485,23 @@ </span><span class="cx"> </span><span class="cx"> text = ("INSERT INTO " + insert_stmt.table.fullname + " (" + string.join([c[0].name for c in colparams], ', ') + ")" + </span><span class="cx"> " VALUES (" + string.join([create_param(c[1]) for c in colparams], ', ') + ")") </span><del>- </del><ins>+ </ins><span class="cx"> self.strings[insert_stmt] = text </span><span class="cx"> </span><span class="cx"> def visit_update(self, update_stmt): </span><span class="cx"> # scan the table's columns for onupdates that have to be pre-set for an UPDATE </span><span class="cx"> # add these columns to the parameter list via visit_update_XXX methods </span><ins>+ default_params = {} </ins><span class="cx"> class OnUpdateVisitor(schema.SchemaVisitor): </span><span class="cx"> def visit_column_onupdate(s, cd): </span><del>- self.visit_update_column_default(c, cd) </del><ins>+ self.visit_update_column_default(c, cd, default_params) </ins><span class="cx"> vis = OnUpdateVisitor() </span><span class="cx"> for c in update_stmt.table.c: </span><span class="cx"> if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): </span><span class="cx"> c.accept_schema_visitor(vis) </span><span class="cx"> </span><span class="cx"> self.isupdate = True </span><del>- colparams = self._get_colparams(update_stmt) </del><ins>+ colparams = self._get_colparams(update_stmt, default_params) </ins><span class="cx"> def create_param(p): </span><span class="cx"> if isinstance(p, sql.BindParamClause): </span><span class="cx"> self.binds[p.key] = p </span><span class="lines">@@ -520,7 +522,7 @@ </span><span class="cx"> self.strings[update_stmt] = text </span><span class="cx"> </span><span class="cx"> </span><del>- def _get_colparams(self, stmt): </del><ins>+ def _get_colparams(self, stmt, default_params): </ins><span class="cx"> """determines the VALUES or SET clause for an INSERT or UPDATE </span><span class="cx"> clause based on the arguments specified to this ANSICompiler object </span><span class="cx"> (i.e., the execute() or compile() method clause object): </span><span class="lines">@@ -551,6 +553,9 @@ </span><span class="cx"> for k, v in stmt.parameters.iteritems(): </span><span class="cx"> parameters.setdefault(k, v) </span><span class="cx"> </span><ins>+ for k, v in default_params.iteritems(): + parameters.setdefault(k, v) + </ins><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py (1353 => 1354)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py 2006-04-28 23:31:59 UTC (rev 1353) +++ sqlalchemy/branches/schema/lib/sqlalchemy/databases/postgres.py 2006-04-29 00:08:07 UTC (rev 1354) </span><span class="lines">@@ -288,13 +288,13 @@ </span><span class="cx"> </span><span class="cx"> class PGCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><del>- def visit_insert_column(self, column): </del><ins>+ def visit_insert_column(self, column, parameters): </ins><span class="cx"> # Postgres advises against OID usage and turns it off in 8.1, </span><span class="cx"> # effectively making cursor.lastrowid </span><span class="cx"> # useless, effectively making reliance upon SERIAL useless. </span><span class="cx"> # so all column primary key inserts must be explicitly present </span><span class="cx"> if column.primary_key: </span><del>- self.parameters[column.key] = None </del><ins>+ parameters[column.key] = None </ins><span class="cx"> </span><span class="cx"> def limit_clause(self, select): </span><span class="cx"> text = "" </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyenginebasepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py (1353 => 1354)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-04-28 23:31:59 UTC (rev 1353) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/base.py 2006-04-29 00:08:07 UTC (rev 1354) </span><span class="lines">@@ -276,12 +276,16 @@ </span><span class="cx"> self.engine.dialect.do_execute(c, statement, parameters, context=context) </span><span class="cx"> except Exception, e: </span><span class="cx"> self.engine.dialect.do_rollback(self.connection) </span><ins>+ if self.close_with_result: + self.close() </ins><span class="cx"> raise exceptions.SQLError(statement, parameters, e) </span><span class="cx"> def _executemany(self, c, statement, parameters, context=None): </span><span class="cx"> try: </span><span class="cx"> self.engine.dialect.do_executemany(c, statement, parameters, context=context) </span><span class="cx"> except Exception, e: </span><span class="cx"> self.engine.dialect.do_rollback(self.connection) </span><ins>+ if self.close_with_result: + self.close() </ins><span class="cx"> raise exceptions.SQLError(statement, parameters, e) </span><span class="cx"> def proxy(self, statement=None, parameters=None): </span><span class="cx"> """executes the given statement string and parameter object. </span><span class="lines">@@ -349,7 +353,7 @@ </span><span class="cx"> """drops a table or index within this engine's database connection given a schema.Table object.""" </span><span class="cx"> self._run_visitor(self.dialect.schemadropper, entity, connection=connection, **kwargs) </span><span class="cx"> def execute_default(self, default, **kwargs): </span><del>- connection = self.connect() </del><ins>+ connection = self.contextual_connect(close_with_result=False) </ins><span class="cx"> try: </span><span class="cx"> return connection.execute_default(default, **kwargs) </span><span class="cx"> finally: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/schema.py (1353 => 1354)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-04-28 23:31:59 UTC (rev 1353) +++ sqlalchemy/branches/schema/lib/sqlalchemy/schema.py 2006-04-29 00:08:07 UTC (rev 1354) </span><span class="lines">@@ -453,12 +453,17 @@ </span><span class="cx"> </span><span class="cx"> class DefaultGenerator(SchemaItem): </span><span class="cx"> """Base class for column "default" values.""" </span><del>- def __init__(self, for_update=False): </del><ins>+ def __init__(self, for_update=False, metadata=None): </ins><span class="cx"> self.for_update = for_update </span><ins>+ self._metadata = metadata </ins><span class="cx"> def _derived_metadata(self): </span><del>- return self.column.table.metadata </del><ins>+ try: + return self.column.table.metadata + except AttributeError: + return self._metadata </ins><span class="cx"> def _set_parent(self, column): </span><span class="cx"> self.column = column </span><ins>+ self._metadata = self.column.table.metadata </ins><span class="cx"> if self.for_update: </span><span class="cx"> self.column.onupdate = self </span><span class="cx"> else: </span></span></pre></div> <a id="sqlalchemybranchesschematestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/defaults.py (1353 => 1354)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/defaults.py 2006-04-28 23:31:59 UTC (rev 1353) +++ sqlalchemy/branches/schema/test/defaults.py 2006-04-29 00:08:07 UTC (rev 1354) </span><span class="lines">@@ -72,7 +72,7 @@ </span><span class="cx"> t.delete().execute() </span><span class="cx"> </span><span class="cx"> def teststandalone(self): </span><del>- c = db.engine.connect() </del><ins>+ c = db.engine.contextual_connect() </ins><span class="cx"> x = c.execute(t.c.col1.default) </span><span class="cx"> y = t.c.col2.default.execute() </span><span class="cx"> z = c.execute(t.c.col3.default) </span><span class="lines">@@ -93,6 +93,12 @@ </span><span class="cx"> l = t.select().execute() </span><span class="cx"> self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts, ctexec), (52, 'imthedefault', f, ts, ts, ctexec), (53, 'imthedefault', f, ts, ts, ctexec)]) </span><span class="cx"> </span><ins>+ def testinsertvalues(self): + t.insert(values={'col3':50}).execute() + l = t.select().execute() + self.assert_(l.fetchone()['col3'] == 50) + + </ins><span class="cx"> def testupdate(self): </span><span class="cx"> r = t.insert().execute() </span><span class="cx"> pk = r.last_inserted_ids()[0] </span><span class="lines">@@ -104,6 +110,14 @@ </span><span class="cx"> self.assert_(l == (pk, 'im the update', f2, None, None, ctexec)) </span><span class="cx"> # mysql/other db's return 0 or 1 for count(1) </span><span class="cx"> self.assert_(14 <= f2 <= 15) </span><ins>+ + def testupdatevalues(self): + r = t.insert().execute() + pk = r.last_inserted_ids()[0] + t.update(t.c.col1==pk, values={'col3': 55}).execute() + l = t.select(t.c.col1==pk).execute() + l = l.fetchone() + self.assert_(l['col3'] == 55) </ins><span class="cx"> </span><span class="cx"> class SequenceTest(PersistTest): </span><span class="cx"> </span><span class="lines">@@ -128,10 +142,10 @@ </span><span class="cx"> </span><span class="cx"> </span><span class="cx"> def teststandalone(self): </span><del>- s = Sequence("my_sequence", engine=db) </del><ins>+ s = Sequence("my_sequence", metadata=testbase.db) </ins><span class="cx"> s.create() </span><span class="cx"> try: </span><del>- x =s.execute() </del><ins>+ x = s.execute() </ins><span class="cx"> self.assert_(x == 1) </span><span class="cx"> finally: </span><span class="cx"> s.drop() </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 23:32:17
|
<!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>[1353] sqlalchemy/trunk/test: fix for [ticket:169], moves the creation of "default" parameters more accurately</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1353</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 18:31:59 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>fix for [ticket:169], moves the creation of "default" parameters more accurately where theyre supposed to be</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemydatabasespostgrespy">sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py</a></li> <li><a href="#sqlalchemytrunktestdefaultspy">sqlalchemy/trunk/test/defaults.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1352 => 1353)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-04-28 22:42:58 UTC (rev 1352) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-04-28 23:31:59 UTC (rev 1353) </span><span class="lines">@@ -146,7 +146,6 @@ </span><span class="cx"> continue </span><span class="cx"> d.set_parameter(b.key, value, b) </span><span class="cx"> </span><del>- #print "FROM", params, "TO", d </del><span class="cx"> return d </span><span class="cx"> </span><span class="cx"> def get_named_params(self, parameters): </span><span class="lines">@@ -425,26 +424,26 @@ </span><span class="cx"> " ON " + self.get_str(join.onclause)) </span><span class="cx"> self.strings[join] = self.froms[join] </span><span class="cx"> </span><del>- def visit_insert_column_default(self, column, default): </del><ins>+ def visit_insert_column_default(self, column, default, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><span class="cx"> contains a ColumnDefault object. adds a blank 'placeholder' parameter so the </span><span class="cx"> Insert gets compiled with this column's name in its column and VALUES clauses.""" </span><del>- self.parameters.setdefault(column.key, None) </del><ins>+ parameters.setdefault(column.key, None) </ins><span class="cx"> </span><del>- def visit_update_column_default(self, column, default): </del><ins>+ def visit_update_column_default(self, column, default, parameters): </ins><span class="cx"> """called when visiting an Update statement, for each column in the table that </span><span class="cx"> contains a ColumnDefault object as an onupdate. adds a blank 'placeholder' parameter so the </span><span class="cx"> Update gets compiled with this column's name as one of its SET clauses.""" </span><del>- self.parameters.setdefault(column.key, None) </del><ins>+ parameters.setdefault(column.key, None) </ins><span class="cx"> </span><del>- def visit_insert_sequence(self, column, sequence): </del><ins>+ def visit_insert_sequence(self, column, sequence, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table that </span><span class="cx"> contains a Sequence object. Overridden by compilers that support sequences to place </span><span class="cx"> a blank 'placeholder' parameter, so the Insert gets compiled with this column's </span><span class="cx"> name in its column and VALUES clauses.""" </span><span class="cx"> pass </span><span class="cx"> </span><del>- def visit_insert_column(self, column): </del><ins>+ def visit_insert_column(self, column, parameters): </ins><span class="cx"> """called when visiting an Insert statement, for each column in the table </span><span class="cx"> that is a NULL insert into the table. Overridden by compilers who disallow </span><span class="cx"> NULL columns being set in an Insert where there is a default value on the column </span><span class="lines">@@ -454,25 +453,27 @@ </span><span class="cx"> def visit_insert(self, insert_stmt): </span><span class="cx"> # scan the table's columns for defaults that have to be pre-set for an INSERT </span><span class="cx"> # add these columns to the parameter list via visit_insert_XXX methods </span><ins>+ default_params = {} </ins><span class="cx"> class DefaultVisitor(schema.SchemaVisitor): </span><span class="cx"> def visit_column(s, c): </span><del>- self.visit_insert_column(c) </del><ins>+ self.visit_insert_column(c, default_params) </ins><span class="cx"> def visit_column_default(s, cd): </span><del>- self.visit_insert_column_default(c, cd) </del><ins>+ self.visit_insert_column_default(c, cd, default_params) </ins><span class="cx"> def visit_sequence(s, seq): </span><del>- self.visit_insert_sequence(c, seq) </del><ins>+ self.visit_insert_sequence(c, seq, default_params) </ins><span class="cx"> vis = DefaultVisitor() </span><span class="cx"> for c in insert_stmt.table.c: </span><span class="cx"> if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): </span><span class="cx"> c.accept_schema_visitor(vis) </span><span class="cx"> </span><span class="cx"> self.isinsert = True </span><del>- colparams = self._get_colparams(insert_stmt) </del><ins>+ colparams = self._get_colparams(insert_stmt, default_params) </ins><span class="cx"> </span><span class="cx"> def create_param(p): </span><span class="cx"> if isinstance(p, sql.BindParamClause): </span><span class="cx"> self.binds[p.key] = p </span><del>- self.binds[p.shortname] = p </del><ins>+ if p.shortname is not None: + self.binds[p.shortname] = p </ins><span class="cx"> return self.bindparam_string(p.key) </span><span class="cx"> else: </span><span class="cx"> p.accept_visitor(self) </span><span class="lines">@@ -483,22 +484,23 @@ </span><span class="cx"> </span><span class="cx"> text = ("INSERT INTO " + insert_stmt.table.fullname + " (" + string.join([c[0].name for c in colparams], ', ') + ")" + </span><span class="cx"> " VALUES (" + string.join([create_param(c[1]) for c in colparams], ', ') + ")") </span><del>- </del><ins>+ </ins><span class="cx"> self.strings[insert_stmt] = text </span><span class="cx"> </span><span class="cx"> def visit_update(self, update_stmt): </span><span class="cx"> # scan the table's columns for onupdates that have to be pre-set for an UPDATE </span><span class="cx"> # add these columns to the parameter list via visit_update_XXX methods </span><ins>+ default_params = {} </ins><span class="cx"> class OnUpdateVisitor(schema.SchemaVisitor): </span><span class="cx"> def visit_column_onupdate(s, cd): </span><del>- self.visit_update_column_default(c, cd) </del><ins>+ self.visit_update_column_default(c, cd, default_params) </ins><span class="cx"> vis = OnUpdateVisitor() </span><span class="cx"> for c in update_stmt.table.c: </span><span class="cx"> if (isinstance(c, schema.SchemaItem) and (self.parameters is None or self.parameters.get(c.key, None) is None)): </span><span class="cx"> c.accept_schema_visitor(vis) </span><span class="cx"> </span><span class="cx"> self.isupdate = True </span><del>- colparams = self._get_colparams(update_stmt) </del><ins>+ colparams = self._get_colparams(update_stmt, default_params) </ins><span class="cx"> def create_param(p): </span><span class="cx"> if isinstance(p, sql.BindParamClause): </span><span class="cx"> self.binds[p.key] = p </span><span class="lines">@@ -519,7 +521,7 @@ </span><span class="cx"> self.strings[update_stmt] = text </span><span class="cx"> </span><span class="cx"> </span><del>- def _get_colparams(self, stmt): </del><ins>+ def _get_colparams(self, stmt, default_params): </ins><span class="cx"> """determines the VALUES or SET clause for an INSERT or UPDATE </span><span class="cx"> clause based on the arguments specified to this ANSICompiler object </span><span class="cx"> (i.e., the execute() or compile() method clause object): </span><span class="lines">@@ -550,6 +552,9 @@ </span><span class="cx"> for k, v in stmt.parameters.iteritems(): </span><span class="cx"> parameters.setdefault(k, v) </span><span class="cx"> </span><ins>+ for k, v in default_params.iteritems(): + parameters.setdefault(k, v) + </ins><span class="cx"> # now go thru compiled params, get the Column object for each key </span><span class="cx"> d = {} </span><span class="cx"> for key, value in parameters.iteritems(): </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemydatabasespostgrespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py (1352 => 1353)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-04-28 22:42:58 UTC (rev 1352) +++ sqlalchemy/trunk/lib/sqlalchemy/databases/postgres.py 2006-04-28 23:31:59 UTC (rev 1353) </span><span class="lines">@@ -291,13 +291,13 @@ </span><span class="cx"> class PGCompiler(ansisql.ANSICompiler): </span><span class="cx"> </span><span class="cx"> </span><del>- def visit_insert_column(self, column): </del><ins>+ def visit_insert_column(self, column, parameters): </ins><span class="cx"> # Postgres advises against OID usage and turns it off in 8.1, </span><span class="cx"> # effectively making cursor.lastrowid </span><span class="cx"> # useless, effectively making reliance upon SERIAL useless. </span><span class="cx"> # so all column primary key inserts must be explicitly present </span><span class="cx"> if column.primary_key: </span><del>- self.parameters[column.key] = None </del><ins>+ parameters[column.key] = None </ins><span class="cx"> </span><span class="cx"> def limit_clause(self, select): </span><span class="cx"> text = "" </span></span></pre></div> <a id="sqlalchemytrunktestdefaultspy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/defaults.py (1352 => 1353)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/defaults.py 2006-04-28 22:42:58 UTC (rev 1352) +++ sqlalchemy/trunk/test/defaults.py 2006-04-28 23:31:59 UTC (rev 1353) </span><span class="lines">@@ -92,6 +92,12 @@ </span><span class="cx"> l = t.select().execute() </span><span class="cx"> self.assert_(l.fetchall() == [(51, 'imthedefault', f, ts, ts, ctexec), (52, 'imthedefault', f, ts, ts, ctexec), (53, 'imthedefault', f, ts, ts, ctexec)]) </span><span class="cx"> </span><ins>+ def testinsertvalues(self): + t.insert(values={'col3':50}).execute() + l = t.select().execute() + self.assert_(l.fetchone()['col3'] == 50) + + </ins><span class="cx"> def testupdate(self): </span><span class="cx"> t.insert().execute() </span><span class="cx"> pk = t.engine.last_inserted_ids()[0] </span><span class="lines">@@ -103,6 +109,14 @@ </span><span class="cx"> self.assert_(l == (pk, 'im the update', f2, None, None, ctexec)) </span><span class="cx"> # mysql/other db's return 0 or 1 for count(1) </span><span class="cx"> self.assert_(14 <= f2 <= 15) </span><ins>+ + def testupdatevalues(self): + t.insert().execute() + pk = t.engine.last_inserted_ids()[0] + t.update(t.c.col1==pk, values={'col3': 55}).execute() + l = t.select(t.c.col1==pk).execute() + l = l.fetchone() + self.assert_(l['col3'] == 55) </ins><span class="cx"> </span><span class="cx"> class SequenceTest(PersistTest): </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 22:43:11
|
<!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>[1352] sqlalchemy/branches/schema/CHANGES: dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1352</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 17:42:58 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaCHANGES">sqlalchemy/branches/schema/CHANGES</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/CHANGES (1351 => 1352)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/CHANGES 2006-04-28 22:33:36 UTC (rev 1351) +++ sqlalchemy/branches/schema/CHANGES 2006-04-28 22:42:58 UTC (rev 1352) </span><span class="lines">@@ -28,6 +28,7 @@ </span><span class="cx"> solely by an explicit Connection object. the "bound" methodlogy exists via the </span><span class="cx"> BoundMetaData for schema objects. ProxyEngine is generally not needed </span><span class="cx"> anymore and is replaced by DynamicMetaData. </span><ins>+- true polymorphic behavior implemented, fixes [ticket:167] </ins><span class="cx"> - "oid" system has been totally moved into compile-time behavior; </span><span class="cx"> if they are used in an order_by where they are not available, the order_by </span><span class="cx"> doesnt get compiled, fixes [ticket:147] </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 22:33:44
|
<!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>[1351] sqlalchemy/branches/schema/lib/sqlalchemy/orm: added auto polymorphic_ident setting</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1351</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 17:33:36 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>added auto polymorphic_ident setting</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1350 => 1351)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-28 22:11:52 UTC (rev 1350) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-28 22:33:36 UTC (rev 1351) </span><span class="lines">@@ -16,7 +16,8 @@ </span><span class="cx"> people = Table('people', db, </span><span class="cx"> Column('person_id', Integer, primary_key=True), </span><span class="cx"> Column('company_id', Integer, ForeignKey('companies.company_id')), </span><del>- Column('name', String(50))).create() </del><ins>+ Column('name', String(50)), + Column('type', String(30))).create() </ins><span class="cx"> </span><span class="cx"> engineers = Table('engineers', db, </span><span class="cx"> Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), </span><span class="lines">@@ -56,28 +57,38 @@ </span><span class="cx"> # create a union that represents both types of joins. we have to use </span><span class="cx"> # nulls to pad out the disparate columns. </span><span class="cx"> person_join = select( </span><del>- [ - people, - managers.c.status, - managers.c.manager_name, - null().label('engineer_name'), - null().label('primary_language'), - column("'manager'").label('type') - ], - people.c.person_id==managers.c.person_id).union_all( - select( - [ - people, - engineers.c.status, - null().label('').label('manager_name'), - engineers.c.engineer_name, - engineers.c.primary_language, - column("'engineer'").label('type') - ], - people.c.person_id==engineers.c.person_id)).alias('pjoin') </del><ins>+ [ + people, + managers.c.status, + managers.c.manager_name, + null().label('engineer_name'), + null().label('primary_language'), + ], + people.c.person_id==managers.c.person_id + ).union_all( + select( + [ + people, + engineers.c.status, + null().label('').label('manager_name'), + engineers.c.engineer_name, + engineers.c.primary_language, + ], + people.c.person_id==engineers.c.person_id + ).union_all( + select( + [ + people, + null().label('').label('status'), + null().label('').label('manager_name'), + null().label('engineer_name'), + null().label('primary_language'), + ], + ) + ) + ).alias('pjoin') </ins><span class="cx"> </span><del>- -person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type) </del><ins>+person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type, polymorphic_ident='person') </ins><span class="cx"> mapper(Engineer, engineers, inherits=person_mapper, polymorphic_ident='engineer') </span><span class="cx"> mapper(Manager, managers, inherits=person_mapper, polymorphic_ident='manager') </span><span class="cx"> </span><span class="lines">@@ -89,6 +100,7 @@ </span><span class="cx"> c = Company(name='company1') </span><span class="cx"> c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1')) </span><span class="cx"> c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java')) </span><ins>+c.employees.append(Person(name='joesmith', status='HHH')) </ins><span class="cx"> c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python')) </span><span class="cx"> c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2')) </span><span class="cx"> session.save(c) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1350 => 1351)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 22:11:52 UTC (rev 1350) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 22:33:36 UTC (rev 1351) </span><span class="lines">@@ -133,12 +133,19 @@ </span><span class="cx"> self.inherits = inherits </span><span class="cx"> if polymorphic_ident is not None: </span><span class="cx"> inherits.add_polymorphic_mapping(polymorphic_ident, self) </span><ins>+ self.polymorphic_ident = polymorphic_ident + if self.polymorphic_on is None: + self.effective_polymorphic_on = inherits.effective_polymorphic_on + else: + self.effective_polymorphic_on = self.polymorphic_on </ins><span class="cx"> else: </span><span class="cx"> self._synchronizer = None </span><span class="cx"> self.inherits = None </span><span class="cx"> self.mapped_table = self.local_table </span><span class="cx"> if polymorphic_ident is not None: </span><del>- raise ArgumentError("'polymorphic_ident' argument can only be used with inherits=<somemapper>") </del><ins>+ self.add_polymorphic_mapping(polymorphic_ident, self) + self.polymorphic_ident = polymorphic_ident + self.effective_polymorphic_on = self.polymorphic_on </ins><span class="cx"> </span><span class="cx"> if select_table is not None: </span><span class="cx"> self.select_table = select_table </span><span class="lines">@@ -596,6 +603,12 @@ </span><span class="cx"> value = self._getattrbycolumn(obj, col) </span><span class="cx"> if value is not None: </span><span class="cx"> params[col.key] = value </span><ins>+ elif self.effective_polymorphic_on is not None and col.original is self.effective_polymorphic_on.original: + print "YA YA ITS", self.polymorphic_ident + if isinsert: + value = self.polymorphic_ident + if col.default is None or value is not None: + params[col.key] = value </ins><span class="cx"> else: </span><span class="cx"> # column is not a primary key ? </span><span class="cx"> if not isinsert: </span><span class="lines">@@ -760,7 +773,6 @@ </span><span class="cx"> </span><span class="cx"> if self.polymorphic_on is not None: </span><span class="cx"> discriminator = row[self.polymorphic_on] </span><del>- print self.polymorphic_map </del><span class="cx"> mapper = self.polymorphic_map[discriminator] </span><span class="cx"> if mapper is not self: </span><span class="cx"> row = self.translate_row(mapper, row) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 22:12:00
|
<!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>[1350] sqlalchemy/branches/schema/examples/polymorph: this is now the basic polymorphic example</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1350</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 17:11:52 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>this is now the basic polymorphic example</pre> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> </ul> <h3>Removed Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorph2py">sqlalchemy/branches/schema/examples/polymorph/polymorph2.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpyfromrev1349sqlalchemybranchesschemaexamplespolymorphpolymorph2py"></a> <div class="copfile"><h4>Copied: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (from rev 1349, sqlalchemy/branches/schema/examples/polymorph/polymorph2.py) ( => )</h4> <pre class="diff"><span> <span class="info">Deleted: sqlalchemy/branches/schema/examples/polymorph/polymorph2.py =================================================================== </span><del>--- sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 22:11:28 UTC (rev 1349) </del><ins>+++ sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 22:11:52 UTC (rev 1350) </ins><span class="lines">@@ -1,125 +0,0 @@ </span><del>-from sqlalchemy import * -import sys - -# this example illustrates a polymorphic load of two classes, where each class has a very -# different set of properties - -db = create_engine('sqlite://', echo=True, echo_uow=False) - -# a table to store companies -companies = Table('companies', db, - Column('company_id', Integer, primary_key=True), - Column('name', String(50))).create() - -# we will define an inheritance relationship between the table "people" and "engineers", -# and a second inheritance relationship between the table "people" and "managers" -people = Table('people', db, - Column('person_id', Integer, primary_key=True), - Column('company_id', Integer, ForeignKey('companies.company_id')), - Column('name', String(50))).create() - -engineers = Table('engineers', db, - Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), - Column('status', String(30)), - Column('engineer_name', String(50)), - Column('primary_language', String(50)), - ).create() - -managers = Table('managers', db, - Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), - Column('status', String(30)), - Column('manager_name', String(50)) - ).create() - - -# create our classes. The Engineer and Manager classes extend from Person. -class Person(object): - def __init__(self, **kwargs): - for key, value in kwargs.iteritems(): - setattr(self, key, value) - def __repr__(self): - return "Ordinary person %s" % self.name -class Engineer(Person): - def __repr__(self): - return "Engineer %s, status %s, engineer_name %s, primary_language %s" % (self.name, self.status, self.engineer_name, self.primary_language) -class Manager(Person): - def __repr__(self): - return "Manager %s, status %s, manager_name %s" % (self.name, self.status, self.manager_name) -class Company(object): - def __init__(self, **kwargs): - for key, value in kwargs.iteritems(): - setattr(self, key, value) - def __repr__(self): - return "Company %s" % self.name - - -# create a union that represents both types of joins. we have to use -# nulls to pad out the disparate columns. -person_join = select( - [ - people, - managers.c.status, - managers.c.manager_name, - null().label('engineer_name'), - null().label('primary_language'), - column("'manager'").label('type') - ], - people.c.person_id==managers.c.person_id).union_all( - select( - [ - people, - engineers.c.status, - null().label('').label('manager_name'), - engineers.c.engineer_name, - engineers.c.primary_language, - column("'engineer'").label('type') - ], - people.c.person_id==engineers.c.person_id)).alias('pjoin') - - -person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type) -mapper(Engineer, engineers, inherits=person_mapper, polymorphic_ident='engineer') -mapper(Manager, managers, inherits=person_mapper, polymorphic_ident='manager') - -mapper(Company, companies, properties={ - 'employees': relation(Person, lazy=True, private=True, backref='company') -}) - -session = create_session() -c = Company(name='company1') -c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1')) -c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java')) -c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python')) -c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2')) -session.save(c) -session.flush() - -session.clear() - -c = session.query(Company).get(1) -for e in c.employees: - print e, e._instance_key, e.company - -print "\n" - -dilbert = session.query(Person).get_by(name='dilbert') -dilbert2 = session.query(Engineer).get_by(name='dilbert') -assert dilbert is dilbert2 - -dilbert.engineer_name = 'hes dibert!' - -session.flush() -session.clear() - -c = session.query(Company).get(1) -for e in c.employees: - print e, e._instance_key - -session.delete(c) -session.flush() - - -managers.drop() -engineers.drop() -people.drop() -companies.drop() </del></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 22:11:43
|
<!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>[1349] sqlalchemy/branches/schema/test: an overhaul to mapper table attributes to allow more flexible breaking up of mapped_table vs.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1349</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 17:11:28 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>an overhaul to mapper table attributes to allow more flexible breaking up of mapped_table vs. select_table; the real polymorphic approach seems to work now</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorph2py">sqlalchemy/branches/schema/examples/polymorph/polymorph2.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormquerypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormsessionpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py</a></li> <li><a href="#sqlalchemybranchesschematestinheritancepy">sqlalchemy/branches/schema/test/inheritance.py</a></li> <li><a href="#sqlalchemybranchesschematestmapperpy">sqlalchemy/branches/schema/test/mapper.py</a></li> <li><a href="#sqlalchemybranchesschematestselectpy">sqlalchemy/branches/schema/test/select.py</a></li> </ul> <h3>Removed Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="delfile"><h4>Deleted: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -1,156 +0,0 @@ </span><del>-from sqlalchemy import * -import sys - -# this example illustrates how to create a relationship to a list of objects, -# where each object in the list has a different type. The typed objects will -# extend from a common base class, although this same approach can be used -# with - -db = create_engine('sqlite://', echo=True, echo_uow=False) -#db = create_engine('postgres://user=scott&password=tiger&host=127.0.0.1&database=test', echo=True, echo_uow=False) - -# a table to store companies -companies = Table('companies', db, - Column('company_id', Integer, primary_key=True), - Column('name', String(50))).create() - -# we will define an inheritance relationship between the table "people" and "engineers", -# and a second inheritance relationship between the table "people" and "managers" -people = Table('people', db, - Column('person_id', Integer, primary_key=True), - Column('company_id', Integer, ForeignKey('companies.company_id')), - Column('name', String(50))).create() - -engineers = Table('engineers', db, - Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), - Column('special_description', String(50))).create() - -managers = Table('managers', db, - Column('person_id', Integer, ForeignKey('people.person_id'), primary_key=True), - Column('description', String(50))).create() - - -# create our classes. The Engineer and Manager classes extend from Person. -class Person(object): - def __init__(self, **kwargs): - for key, value in kwargs.iteritems(): - setattr(self, key, value) - def __repr__(self): - return "Ordinary person %s" % self.name -class Engineer(Person): - def __repr__(self): - return "Engineer %s, description %s" % (self.name, self.special_description) -class Manager(Person): - def __repr__(self): - return "Manager %s, description %s" % (self.name, self.description) -class Company(object): - def __init__(self, **kwargs): - for key, value in kwargs.iteritems(): - setattr(self, key, value) - def __repr__(self): - return "Company %s" % self.name - -# next we assign Person mappers. Since these are the first mappers we are -# creating for these classes, they automatically become the "primary mappers", which -# define the dependency relationships between the classes, so we do a straight -# inheritance setup, i.e. no modifications to how objects are loaded or anything like that. -mapper(Person, people) -mapper(Engineer, engineers, inherits=class_mapper(Person)) -mapper(Manager, managers, inherits=class_mapper(Person)) - -# next, we define a query that is going to load Managers and Engineers in one shot. -# we will use a UNION ALL with an extra hardcoded column to indicate the type of object. -# this can also be done via several LEFT OUTER JOINS but a UNION is more appropriate -# since they are distinct result sets. -# The select() statement is also given an alias 'pjoin', since the mapper requires -# that all Selectables have a name. -# -# TECHNIQUE - when you want to load a certain set of objects from a in one query, all the -# columns in the Selectable must have unique names. Dont worry about mappers at this point, -# just worry about making a query where if you were to view the results, you could tell everything -# you need to know from each row how to construct an object instance from it. this is the -# essence of "resultset-based-mapping", which is the core ideology of SQLAlchemy. -# -person_join = select( - [people, managers.c.description,column("'manager'").label('type')], - people.c.person_id==managers.c.person_id).union_all( - select( - [people, engineers.c.special_description.label('description'), column("'engineer'").label('type')], - people.c.person_id==engineers.c.person_id)).alias('pjoin') - - -# lets print out what this Selectable looks like. The mapper is going to take the selectable and -# Select off of it, with the flag "use_labels" which indicates to prefix column names with the table -# name. So here is what our mapper will see: -print "Person selectable:", str(person_join.select(use_labels=True)), "\n" - - -# MapperExtension object. -class PersonLoader(MapperExtension): - def create_instance(self, session, mapper, row, imap, class_): - if row['pjoin_type'] =='engineer': - e = Engineer() - e.special_description = row['pjoin_description'] - return e - elif row['pjoin_type'] =='manager': - return Manager() - else: - return Person() -ext = PersonLoader() - -# set up the polymorphic mapper, which maps the person_join we set up to -# the Person class, using an instance of PersonLoader. -people_mapper = mapper(Person, person_join, extension=ext, non_primary=True) - -# TODO: polymorphic options, i.e.: -# people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}) - -# create a mapper for Company. the 'employees' relationship points to -# our new people_mapper. -# -# the dependency relationships which take effect on commit (i.e. the order of -# inserts/deletes) will be established against the Person class's primary -# mapper, and when the Engineer and -# Manager objects are found in the 'employees' list, the primary mappers -# for those subclasses will register -# themselves as dependent on the Person mapper's save operations. -# (translation: it'll work) -# TODO: get the eager loading to work (the compound select alias doesnt like being aliased itself) -mapper(Company, companies, properties={ - 'employees': relation(people_mapper, lazy=False, cascade="save-update,delete,delete-orphan", backref=backref("company")) -}) - -session = create_session() -c = Company(name='company1') -c.employees.append(Manager(name='pointy haired boss', description='manager1')) -c.employees.append(Engineer(name='dilbert', special_description='engineer1')) -c.employees.append(Engineer(name='wally', special_description='engineer2')) -c.employees.append(Manager(name='jsmith', description='manager2')) -session.save(c) -session.flush() - -session.clear() - -c = session.query(Company).get(1) -for e in c.employees: - print e, e._instance_key - -print "\n" - -dilbert = session.query(Engineer).get_by(name='dilbert') -dilbert.special_description = 'hes dibert!' -session.flush() - -session.clear() -c = session.query(Company).get(1) -for e in c.employees: - print e, e._instance_key, e.company - -session.delete(c) -session.flush() - - -managers.drop() -engineers.drop() -people.drop() -companies.drop() </del></span></pre></div> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorph2py"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph2.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -77,16 +77,12 @@ </span><span class="cx"> people.c.person_id==engineers.c.person_id)).alias('pjoin') </span><span class="cx"> </span><span class="cx"> </span><del>-mapper(Person, people) -mapper(Engineer, engineers, inherits=Person) -mapper(Manager, managers, inherits=Person) - -people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}, non_primary=True) </del><ins>+person_mapper = mapper(Person, people, select_table=person_join, polymorphic_on=person_join.c.type) +mapper(Engineer, engineers, inherits=person_mapper, polymorphic_ident='engineer') +mapper(Manager, managers, inherits=person_mapper, polymorphic_ident='manager') </ins><span class="cx"> </span><del>- - </del><span class="cx"> mapper(Company, companies, properties={ </span><del>- 'employees': relation(people_mapper, lazy=False, private=True, backref='company') </del><ins>+ 'employees': relation(Person, lazy=True, private=True, backref='company') </ins><span class="cx"> }) </span><span class="cx"> </span><span class="cx"> session = create_session() </span><span class="lines">@@ -106,10 +102,8 @@ </span><span class="cx"> </span><span class="cx"> print "\n" </span><span class="cx"> </span><del>-dilbert = session.query(people_mapper).get_by(name='dilbert') -print "DILBERT1", dilbert </del><ins>+dilbert = session.query(Person).get_by(name='dilbert') </ins><span class="cx"> dilbert2 = session.query(Engineer).get_by(name='dilbert') </span><del>-print "DILBERT2", dilbert2 </del><span class="cx"> assert dilbert is dilbert2 </span><span class="cx"> </span><span class="cx"> dilbert.engineer_name = 'hes dibert!' </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -38,7 +38,7 @@ </span><span class="cx"> relation() function.""" </span><span class="cx"> def __init__(self, </span><span class="cx"> class_, </span><del>- table, </del><ins>+ local_table, </ins><span class="cx"> properties = None, </span><span class="cx"> primary_key = None, </span><span class="cx"> is_primary = False, </span><span class="lines">@@ -54,7 +54,7 @@ </span><span class="cx"> polymorphic_on=None, </span><span class="cx"> polymorphic_map=None, </span><span class="cx"> polymorphic_ident=None, </span><del>- selectfrom=None): </del><ins>+ select_table=None): </ins><span class="cx"> </span><span class="cx"> ext = MapperExtension() </span><span class="cx"> </span><span class="lines">@@ -78,77 +78,89 @@ </span><span class="cx"> self.version_id_col = version_id_col </span><span class="cx"> self._inheriting_mappers = sets.Set() </span><span class="cx"> self.polymorphic_on = polymorphic_on </span><del>- self.polymorphic_map = polymorphic_map or {} - </del><ins>+ if polymorphic_map is None: + self.polymorphic_map = {} + else: + self.polymorphic_map = polymorphic_map + </ins><span class="cx"> if not issubclass(class_, object): </span><span class="cx"> raise ArgumentError("Class '%s' is not a new-style class" % class_.__name__) </span><del>- - if isinstance(table, sql.Select): - # some db's, noteably postgres, dont want to select from a select - # without an alias. also if we make our own alias internally, then - # the configured properties on the mapper are not matched against the alias - # we make, theres workarounds but it starts to get really crazy (its crazy enough - # the SQL that gets generated) so just require an alias - raise ArgumentError("Mapping against a Select object requires that it has a name. Use an alias to give it a name, i.e. s = select(...).alias('myselect')") - else: - self.table = table </del><span class="cx"> </span><del>- if selectfrom is None: - self.selectfrom = self.table - else: - self.selectfrom = selectfrom - </del><ins>+ # set up various Selectable units: + + # mapped_table - the Selectable that represents a join of the underlying Tables to be saved (or just the Table) + # local_table - the Selectable that was passed to this Mapper's constructor, if any + # select_table - the Selectable that will be used during queries. if this is specified + # as a constructor keyword argument, it takes precendence over mapped_table, otherwise its mapped_table + # unjoined_table - our Selectable, minus any joins constructed against the inherits table. + # this is either select_table if it was given explicitly, or in the case of a mapper that inherits + # its local_table + # tables - a collection of underlying Table objects pulled from mapped_table + + for table in (local_table, select_table): + if table is not None and isinstance(local_table, sql.Select): + # some db's, noteably postgres, dont want to select from a select + # without an alias. also if we make our own alias internally, then + # the configured properties on the mapper are not matched against the alias + # we make, theres workarounds but it starts to get really crazy (its crazy enough + # the SQL that gets generated) so just require an alias + raise ArgumentError("Mapping against a Select object requires that it has a name. Use an alias to give it a name, i.e. s = select(...).alias('myselect')") + + self.local_table = local_table + </ins><span class="cx"> if inherits is not None: </span><span class="cx"> if isinstance(inherits, type): </span><span class="cx"> inherits = class_mapper(inherits) </span><span class="cx"> if self.class_.__mro__[1] != inherits.class_: </span><span class="cx"> raise ArgumentError("Class '%s' does not inherit from '%s'" % (self.class_.__name__, inherits.class_.__name__)) </span><del>- self.primarytable = inherits.primarytable </del><span class="cx"> # inherit_condition is optional. </span><del>- if not table is inherits.noninherited_table: </del><ins>+ if not local_table is inherits.local_table: </ins><span class="cx"> if inherit_condition is None: </span><span class="cx"> # figure out inherit condition from our table to the immediate table </span><span class="cx"> # of the inherited mapper, not its full table which could pull in other </span><span class="cx"> # stuff we dont want (allows test/inheritance.InheritTest4 to pass) </span><del>- inherit_condition = sql.join(inherits.noninherited_table, table).onclause - self.table = sql.join(inherits.table, table, inherit_condition) </del><ins>+ inherit_condition = sql.join(inherits.local_table, self.local_table).onclause + self.mapped_table = sql.join(inherits.mapped_table, self.local_table, inherit_condition) </ins><span class="cx"> #print "inherit condition", str(self.table.onclause) </span><span class="cx"> </span><span class="cx"> # generate sync rules. similarly to creating the on clause, specify a </span><span class="cx"> # stricter set of tables to create "sync rules" by,based on the immediate </span><span class="cx"> # inherited table, rather than all inherited tables </span><span class="cx"> self._synchronizer = sync.ClauseSynchronizer(self, self, sync.ONETOMANY) </span><del>- self._synchronizer.compile(self.table.onclause, util.HashSet([inherits.noninherited_table]), sqlutil.TableFinder(table)) - # the old rule - #self._synchronizer.compile(self.table.onclause, inherits.tables, TableFinder(table)) </del><ins>+ self._synchronizer.compile(self.mapped_table.onclause, util.HashSet([inherits.local_table]), sqlutil.TableFinder(self.local_table)) </ins><span class="cx"> else: </span><span class="cx"> self._synchronizer = None </span><span class="cx"> self.inherits = inherits </span><del>- self.noninherited_table = table </del><span class="cx"> if polymorphic_ident is not None: </span><span class="cx"> inherits.add_polymorphic_mapping(polymorphic_ident, self) </span><span class="cx"> else: </span><del>- self.primarytable = self.table - self.noninherited_table = self.table </del><span class="cx"> self._synchronizer = None </span><span class="cx"> self.inherits = None </span><ins>+ self.mapped_table = self.local_table </ins><span class="cx"> if polymorphic_ident is not None: </span><span class="cx"> raise ArgumentError("'polymorphic_ident' argument can only be used with inherits=<somemapper>") </span><ins>+ + if select_table is not None: + self.select_table = select_table + self.unjoined_table = self.select_table + else: + self.select_table = self.mapped_table + self.unjoined_table = self.local_table </ins><span class="cx"> </span><span class="cx"> # locate all tables contained within the "table" passed in, which </span><span class="cx"> # may be a join or other construct </span><del>- self.tables = sqlutil.TableFinder(self.table) </del><ins>+ self.tables = sqlutil.TableFinder(self.mapped_table) </ins><span class="cx"> </span><span class="cx"> # determine primary key columns, either passed in, or get them from our set of tables </span><span class="cx"> self.pks_by_table = {} </span><span class="cx"> if primary_key is not None: </span><span class="cx"> for k in primary_key: </span><span class="cx"> self.pks_by_table.setdefault(k.table, util.HashSet(ordered=True)).append(k) </span><del>- if k.table != self.table: </del><ins>+ if k.table != self.mapped_table: </ins><span class="cx"> # associate pk cols from subtables to the "main" table </span><del>- self.pks_by_table.setdefault(self.table, util.HashSet(ordered=True)).append(k) </del><ins>+ self.pks_by_table.setdefault(self.mapped_table, util.HashSet(ordered=True)).append(k) </ins><span class="cx"> else: </span><del>- for t in self.tables + [self.table]: </del><ins>+ for t in self.tables + [self.mapped_table, self.select_table]: </ins><span class="cx"> try: </span><span class="cx"> l = self.pks_by_table[t] </span><span class="cx"> except KeyError: </span><span class="lines">@@ -177,7 +189,7 @@ </span><span class="cx"> </span><span class="cx"> # load properties from the main table object, </span><span class="cx"> # not overriding those set up in the 'properties' argument </span><del>- for column in self.table.columns: </del><ins>+ for column in self.select_table.columns: </ins><span class="cx"> if not self.columns.has_key(column.key): </span><span class="cx"> self.columns[column.key] = column </span><span class="cx"> </span><span class="lines">@@ -206,7 +218,7 @@ </span><span class="cx"> proplist = self.columntoproperty.setdefault(column.original, []) </span><span class="cx"> proplist.append(prop) </span><span class="cx"> </span><del>- if not mapper_registry.has_key(self.class_key) or self.is_primary or (inherits is not None and inherits._is_primary_mapper()): </del><ins>+ if not non_primary and (not mapper_registry.has_key(self.class_key) or self.is_primary or (inherits is not None and inherits._is_primary_mapper())): </ins><span class="cx"> sessionlib.global_attributes.reset_class_managed(self.class_) </span><span class="cx"> self._init_class() </span><span class="cx"> elif not non_primary: </span><span class="lines">@@ -215,7 +227,7 @@ </span><span class="cx"> for key in self.polymorphic_map.keys(): </span><span class="cx"> if isinstance(self.polymorphic_map[key], type): </span><span class="cx"> self.polymorphic_map[key] = class_mapper(self.polymorphic_map[key]) </span><del>- </del><ins>+ </ins><span class="cx"> if inherits is not None: </span><span class="cx"> inherits._inheriting_mappers.add(self) </span><span class="cx"> for key, prop in inherits.props.iteritems(): </span><span class="lines">@@ -228,6 +240,7 @@ </span><span class="cx"> if getattr(prop, 'key', None) is None: </span><span class="cx"> prop.init(key, self) </span><span class="cx"> </span><ins>+ </ins><span class="cx"> # this prints a summary of the object attributes and how they </span><span class="cx"> # will be mapped to table columns </span><span class="cx"> #print "mapper %s, columntoproperty:" % (self.class_.__name__) </span><span class="lines">@@ -323,14 +336,14 @@ </span><span class="cx"> </span><span class="cx"> if sql.is_column(prop): </span><span class="cx"> try: </span><del>- prop = self.table._get_col_by_original(prop) </del><ins>+ prop = self.select_table._get_col_by_original(prop) </ins><span class="cx"> except KeyError: </span><span class="cx"> raise ArgumentError("Column '%s' is not represented in mapper's table" % prop._label) </span><span class="cx"> self.columns[key] = prop </span><span class="cx"> prop = ColumnProperty(prop) </span><span class="cx"> elif isinstance(prop, list) and sql.is_column(prop[0]): </span><span class="cx"> try: </span><del>- prop = [self.table._get_col_by_original(p) for p in prop] </del><ins>+ prop = [self.select_table._get_col_by_original(p) for p in prop] </ins><span class="cx"> except KeyError, e: </span><span class="cx"> raise ArgumentError("Column '%s' is not represented in mapper's table" % e.args[0]) </span><span class="cx"> self.columns[key] = prop[0] </span><span class="lines">@@ -350,7 +363,7 @@ </span><span class="cx"> mapper.add_property(key, p, init=False) </span><span class="cx"> </span><span class="cx"> def __str__(self): </span><del>- return "Mapper|" + self.class_.__name__ + "|" + (self.entity_name is not None and "/%s" % self.entity_name or "") + self.primarytable.name </del><ins>+ return "Mapper|" + self.class_.__name__ + "|" + (self.entity_name is not None and "/%s" % self.entity_name or "") + self.select_table.name </ins><span class="cx"> </span><span class="cx"> def _is_primary_mapper(self): </span><span class="cx"> """returns True if this mapper is the primary mapper for its class key (class + entity_name)""" </span><span class="lines">@@ -456,7 +469,7 @@ </span><span class="cx"> </span><span class="cx"> def identity(self, instance): </span><span class="cx"> """returns the identity (list of primary key values) for the given instance. The list of values can be fed directly into the get() method as mapper.get(*key).""" </span><del>- return [self._getattrbycolumn(instance, column) for column in self.pks_by_table[self.table]] </del><ins>+ return [self._getattrbycolumn(instance, column) for column in self.pks_by_table[self.select_table]] </ins><span class="cx"> </span><span class="cx"> def compile(self, whereclause = None, **options): </span><span class="cx"> """works like select, except returns the SQL statement object without </span><span class="lines">@@ -489,6 +502,8 @@ </span><span class="cx"> if (key.startswith('select_by_') or key.startswith('get_by_')): </span><span class="cx"> return getattr(self.query(), key) </span><span class="cx"> else: </span><ins>+ if key == 'table': + raise "what!? " + key #AttributeError(key) </ins><span class="cx"> raise AttributeError(key) </span><span class="cx"> </span><span class="cx"> def _getpropbycolumn(self, column, raiseerror=True): </span><span class="lines">@@ -735,7 +750,7 @@ </span><span class="cx"> yield c </span><span class="cx"> </span><span class="cx"> def _identity_key(self, row): </span><del>- return sessionlib.get_row_key(row, self.class_, self.pks_by_table[self.table], self.entity_name) </del><ins>+ return sessionlib.get_row_key(row, self.class_, self.pks_by_table[self.select_table], self.entity_name) </ins><span class="cx"> </span><span class="cx"> def _instance(self, session, row, imap, result = None, populate_existing = False): </span><span class="cx"> """pulls an object instance from the given row and appends it to the given result </span><span class="lines">@@ -745,6 +760,7 @@ </span><span class="cx"> </span><span class="cx"> if self.polymorphic_on is not None: </span><span class="cx"> discriminator = row[self.polymorphic_on] </span><ins>+ print self.polymorphic_map </ins><span class="cx"> mapper = self.polymorphic_map[discriminator] </span><span class="cx"> if mapper is not self: </span><span class="cx"> row = self.translate_row(mapper, row) </span><span class="lines">@@ -776,7 +792,7 @@ </span><span class="cx"> if not exists: </span><span class="cx"> # check if primary key cols in the result are None - this indicates </span><span class="cx"> # an instance of the object is not present in the row </span><del>- for col in self.pks_by_table[self.table]: </del><ins>+ for col in self.pks_by_table[self.select_table]: </ins><span class="cx"> if row[col] is None: </span><span class="cx"> return None </span><span class="cx"> # plugin point </span><span class="lines">@@ -820,9 +836,9 @@ </span><span class="cx"> bare keynames to accomplish this. So far this works for the various polymorphic </span><span class="cx"> examples.""" </span><span class="cx"> newrow = util.DictDecorator(row) </span><del>- for c in self.table.c: </del><ins>+ for c in self.select_table.c: </ins><span class="cx"> newrow[c.name] = row[c] </span><del>- for c in tomapper.table.c: </del><ins>+ for c in tomapper.select_table.c: </ins><span class="cx"> newrow[c] = newrow[c.name] </span><span class="cx"> return newrow </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -195,7 +195,7 @@ </span><span class="cx"> if isinstance(self.association, type): </span><span class="cx"> self.association = sqlalchemy.orm.class_mapper(self.association) </span><span class="cx"> </span><del>- self.target = self.mapper.table </del><ins>+ self.target = self.mapper.select_table </ins><span class="cx"> self.key = key </span><span class="cx"> self.parent = parent </span><span class="cx"> </span><span class="lines">@@ -204,12 +204,13 @@ </span><span class="cx"> # if join conditions were not specified, figure them out based on foreign keys </span><span class="cx"> if self.secondary is not None: </span><span class="cx"> if self.secondaryjoin is None: </span><del>- self.secondaryjoin = sql.join(self.mapper.noninherited_table, self.secondary).onclause </del><ins>+ self.secondaryjoin = sql.join(self.mapper.unjoined_table, self.secondary).onclause </ins><span class="cx"> if self.primaryjoin is None: </span><del>- self.primaryjoin = sql.join(parent.noninherited_table, self.secondary).onclause </del><ins>+ self.primaryjoin = sql.join(parent.unjoined_table, self.secondary).onclause </ins><span class="cx"> else: </span><span class="cx"> if self.primaryjoin is None: </span><del>- self.primaryjoin = sql.join(parent.noninherited_table, self.target).onclause </del><ins>+ self.primaryjoin = sql.join(parent.unjoined_table, self.target).onclause + print "PJ", self.primaryjoin </ins><span class="cx"> # if the foreign key wasnt specified and theres no assocaition table, try to figure </span><span class="cx"> # out who is dependent on who. we dont need all the foreign keys represented in the join, </span><span class="cx"> # just one of them. </span><span class="lines">@@ -255,18 +256,18 @@ </span><span class="cx"> </span><span class="cx"> def _get_direction(self): </span><span class="cx"> """determines our 'direction', i.e. do we represent one to many, many to many, etc.""" </span><del>- #print self.key, repr(self.parent.table.name), repr(self.parent.primarytable.name), repr(self.foreignkey.table.name), repr(self.target), repr(self.foreigntable.name) </del><ins>+ #print self.key, repr(self.parent.mapped_table.name), repr(self.parent.primarytable.name), repr(self.foreignkey.table.name), repr(self.target), repr(self.foreigntable.name) </ins><span class="cx"> </span><span class="cx"> if self.secondaryjoin is not None: </span><span class="cx"> return sync.MANYTOMANY </span><del>- elif self.parent.table is self.target: </del><ins>+ elif self.parent.mapped_table is self.target: </ins><span class="cx"> if self.foreignkey.primary_key: </span><span class="cx"> return sync.MANYTOONE </span><span class="cx"> else: </span><span class="cx"> return sync.ONETOMANY </span><del>- elif self.foreigntable == self.mapper.noninherited_table: </del><ins>+ elif self.foreigntable == self.mapper.unjoined_table: </ins><span class="cx"> return sync.ONETOMANY </span><del>- elif self.foreigntable == self.parent.noninherited_table: </del><ins>+ elif self.foreigntable == self.parent.unjoined_table: </ins><span class="cx"> return sync.MANYTOONE </span><span class="cx"> else: </span><span class="cx"> raise ArgumentError("Cant determine relation direction") </span><span class="lines">@@ -316,11 +317,11 @@ </span><span class="cx"> else: </span><span class="cx"> c = (self.mapper.props[key].columns[0]==value) & self.primaryjoin </span><span class="cx"> return c.copy_container() </span><del>- elif self.mapper.table.c.has_key(key): </del><ins>+ elif self.mapper.mapped_table.c.has_key(key): </ins><span class="cx"> if self.secondaryjoin is not None: </span><del>- c = (self.mapper.table.c[key].columns[0]==value) & self.primaryjoin & self.secondaryjoin </del><ins>+ c = (self.mapper.mapped_table.c[key].columns[0]==value) & self.primaryjoin & self.secondaryjoin </ins><span class="cx"> else: </span><del>- c = (self.mapper.table.c[key].columns[0]==value) & self.primaryjoin </del><ins>+ c = (self.mapper.mapped_table.c[key].columns[0]==value) & self.primaryjoin </ins><span class="cx"> return c.copy_container() </span><span class="cx"> elif self.association is not None: </span><span class="cx"> c = query._get_criterion(self.mapper, key, value) & self.primaryjoin </span><span class="lines">@@ -343,8 +344,8 @@ </span><span class="cx"> </span><span class="cx"> The list of rules is used within commits by the _synchronize() method when dependent </span><span class="cx"> objects are processed.""" </span><del>- parent_tables = util.HashSet(self.parent.tables + [self.parent.primarytable]) - target_tables = util.HashSet(self.mapper.tables + [self.mapper.primarytable]) </del><ins>+ parent_tables = util.HashSet(self.parent.tables + [self.parent.mapped_table, self.parent.select_table]) + target_tables = util.HashSet(self.mapper.tables + [self.mapper.mapped_table, self.mapper.select_table]) </ins><span class="cx"> </span><span class="cx"> self.syncrules = sync.ClauseSynchronizer(self.parent, self.mapper, self.direction) </span><span class="cx"> if self.direction == sync.MANYTOMANY: </span><span class="lines">@@ -356,7 +357,7 @@ </span><span class="cx"> </span><span class="cx"> class LazyLoader(PropertyLoader): </span><span class="cx"> def do_init_subclass(self, key, parent): </span><del>- (self.lazywhere, self.lazybinds, self.lazyreverse) = create_lazy_clause(self.parent.noninherited_table, self.primaryjoin, self.secondaryjoin, self.foreignkey) </del><ins>+ (self.lazywhere, self.lazybinds, self.lazyreverse) = create_lazy_clause(self.parent.unjoined_table, self.primaryjoin, self.secondaryjoin, self.foreignkey) </ins><span class="cx"> # determine if our "lazywhere" clause is the same as the mapper's </span><span class="cx"> # get() clause. then we can just use mapper.get() </span><span class="cx"> self.use_get = not self.uselist and self.mapper.query()._get_clause.compare(self.lazywhere) </span><span class="lines">@@ -387,7 +388,7 @@ </span><span class="cx"> # to possibly save a DB round trip </span><span class="cx"> if self.use_get: </span><span class="cx"> ident = [] </span><del>- for primary_key in self.mapper.pks_by_table[self.mapper.table]: </del><ins>+ for primary_key in self.mapper.pks_by_table[self.mapper.select_table]: </ins><span class="cx"> bind = self.lazyreverse[primary_key] </span><span class="cx"> ident.append(params[bind.key]) </span><span class="cx"> return self.mapper.using(session).get(*ident) </span><span class="lines">@@ -500,7 +501,7 @@ </span><span class="cx"> if isinstance(prop, EagerLoader): </span><span class="cx"> eagerprops.append(prop) </span><span class="cx"> if len(eagerprops): </span><del>- recursion_stack[self.parent.table] = True </del><ins>+ recursion_stack[self.parent.mapped_table] = True </ins><span class="cx"> self.mapper = self.mapper.copy() </span><span class="cx"> try: </span><span class="cx"> for prop in eagerprops: </span><span class="lines">@@ -510,16 +511,16 @@ </span><span class="cx"> continue </span><span class="cx"> p = prop.copy() </span><span class="cx"> self.mapper.props[prop.key] = p </span><del>-# print "we are:", id(self), self.target.name, (self.secondary and self.secondary.name or "None"), self.parent.table.name -# print "prop is",id(prop), prop.target.name, (prop.secondary and prop.secondary.name or "None"), prop.parent.table.name </del><ins>+# print "we are:", id(self), self.target.name, (self.secondary and self.secondary.name or "None"), self.parent.mapped_table.name +# print "prop is",id(prop), prop.target.name, (prop.secondary and prop.secondary.name or "None"), prop.parent.mapped_table.name </ins><span class="cx"> p.do_init_subclass(prop.key, prop.parent, recursion_stack) </span><span class="cx"> p._create_eager_chain(in_chain=True, recursion_stack=recursion_stack) </span><span class="cx"> p.eagerprimary = p.eagerprimary.copy_container() </span><del>-# aliasizer = Aliasizer(p.parent.table, aliases={p.parent.table:self.eagertarget}) </del><ins>+# aliasizer = Aliasizer(p.parent.mapped_table, aliases={p.parent.mapped_table:self.eagertarget}) </ins><span class="cx"> p.eagerprimary.accept_visitor(self.aliasizer) </span><del>- #print "new eagertqarget", p.eagertarget.name, (p.secondary and p.secondary.name or "none"), p.parent.table.name </del><ins>+ #print "new eagertqarget", p.eagertarget.name, (p.secondary and p.secondary.name or "none"), p.parent.mapped_table.name </ins><span class="cx"> finally: </span><del>- del recursion_stack[self.parent.table] </del><ins>+ del recursion_stack[self.parent.mapped_table] </ins><span class="cx"> </span><span class="cx"> self._row_decorator = self._create_decorator_row() </span><span class="cx"> </span><span class="lines">@@ -546,7 +547,7 @@ </span><span class="cx"> if hasattr(statement, '_outerjoin'): </span><span class="cx"> towrap = statement._outerjoin </span><span class="cx"> else: </span><del>- towrap = self.parent.table </del><ins>+ towrap = self.parent.mapped_table </ins><span class="cx"> </span><span class="cx"> # print "hello, towrap", str(towrap) </span><span class="cx"> if self.secondaryjoin is not None: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -31,7 +31,7 @@ </span><span class="cx"> return sessionlib.get_session() </span><span class="cx"> else: </span><span class="cx"> return self._session </span><del>- table = property(lambda s:s.mapper.selectfrom) </del><ins>+ table = property(lambda s:s.mapper.select_table) </ins><span class="cx"> props = property(lambda s:s.mapper.props) </span><span class="cx"> session = property(_get_session) </span><span class="cx"> </span><span class="lines">@@ -274,8 +274,8 @@ </span><span class="cx"> list of relations.""" </span><span class="cx"> if mapper.props.has_key(key): </span><span class="cx"> return mapper.props[key].columns[0] == value </span><del>- elif mapper.table.c.has_key(key): - return mapper.table.c[key] == value </del><ins>+ elif mapper.select_table.c.has_key(key): + return mapper.select_table.c[key] == value </ins><span class="cx"> else: </span><span class="cx"> for prop in mapper.props.values(): </span><span class="cx"> c = prop.get_criterion(self, key, value) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -147,12 +147,12 @@ </span><span class="cx"> return self.bind_to </span><span class="cx"> elif self.binds.has_key(mapper): </span><span class="cx"> return self.binds[mapper] </span><del>- elif self.binds.has_key(mapper.table): - return self.binds[mapper.table] </del><ins>+ elif self.binds.has_key(mapper.select_table): + return self.binds[mapper.select_table] </ins><span class="cx"> elif self.bind_to is not None: </span><span class="cx"> return self.bind_to </span><span class="cx"> else: </span><del>- return mapper.table.engine </del><ins>+ return mapper.select_table.engine </ins><span class="cx"> def query(self, mapper_or_class, entity_name=None): </span><span class="cx"> """given a mapper or Class, returns a new Query object corresponding to this Session and the mapper, or the classes' primary mapper.""" </span><span class="cx"> if isinstance(mapper_or_class, type): </span></span></pre></div> <a id="sqlalchemybranchesschematestinheritancepy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/inheritance.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/inheritance.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/test/inheritance.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -1,5 +1,5 @@ </span><ins>+import testbase </ins><span class="cx"> from sqlalchemy import * </span><del>-import testbase </del><span class="cx"> import string </span><span class="cx"> import sqlalchemy.attributes as attr </span><span class="cx"> import sys </span><span class="lines">@@ -374,7 +374,7 @@ </span><span class="cx"> def testbasic(self): </span><span class="cx"> class ContentType(object): pass </span><span class="cx"> class Content(object): pass </span><del>- class Product(object): pass </del><ins>+ class Product(Content): pass </ins><span class="cx"> </span><span class="cx"> content_types = mapper(ContentType, content_type) </span><span class="cx"> contents = mapper(Content, content, properties={ </span><span class="lines">@@ -410,6 +410,7 @@ </span><span class="cx"> foos = mapper(Foo, foo) </span><span class="cx"> bars = mapper(Bar, bar, inherits=foos) </span><span class="cx"> bars.add_property('lazy', relation(foos, bar_foo, lazy=True)) </span><ins>+ print bars.props['lazy'].primaryjoin, bars.props['lazy'].secondaryjoin </ins><span class="cx"> bars.add_property('eager', relation(foos, bar_foo, lazy=False)) </span><span class="cx"> </span><span class="cx"> foo.insert().execute(data='foo1') </span></span></pre></div> <a id="sqlalchemybranchesschematestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/mapper.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/mapper.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/test/mapper.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -570,8 +570,8 @@ </span><span class="cx"> closedorders = alias(orders, 'closedorders') </span><span class="cx"> m = mapper(User, users, properties = dict( </span><span class="cx"> addresses = relation(mapper(Address, addresses), lazy = False), </span><del>- open_orders = relation(mapper(Order, openorders, non_primary=True), primaryjoin = and_(openorders.c.isopen == 1, users.c.user_id==openorders.c.user_id), lazy = True), - closed_orders = relation(mapper(Order, closedorders,non_primary=True), primaryjoin = and_(closedorders.c.isopen == 0, users.c.user_id==closedorders.c.user_id), lazy = True) </del><ins>+ open_orders = relation(mapper(Order, openorders, entity_name='open'), primaryjoin = and_(openorders.c.isopen == 1, users.c.user_id==openorders.c.user_id), lazy = True), + closed_orders = relation(mapper(Order, closedorders,entity_name='closed'), primaryjoin = and_(closedorders.c.isopen == 0, users.c.user_id==closedorders.c.user_id), lazy = True) </ins><span class="cx"> )) </span><span class="cx"> l = m.select() </span><span class="cx"> self.assert_result(l, User, </span></span></pre></div> <a id="sqlalchemybranchesschematestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/select.py (1348 => 1349)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/select.py 2006-04-28 15:02:49 UTC (rev 1348) +++ sqlalchemy/branches/schema/test/select.py 2006-04-28 22:11:28 UTC (rev 1349) </span><span class="lines">@@ -460,7 +460,14 @@ </span><span class="cx"> FROM mytable UNION SELECT myothertable.otherid, myothertable.othername \ </span><span class="cx"> FROM myothertable UNION SELECT thirdtable.userid, thirdtable.otherstuff FROM thirdtable") </span><span class="cx"> </span><ins>+ u = union( + select([table1]), + select([table2]), + select([table3]) + ) + assert u._get_col_by_original(table2.c.otherid) is u.c.otherid </ins><span class="cx"> </span><ins>+ </ins><span class="cx"> def testouterjoin(self): </span><span class="cx"> # test an outer join. the oracle module should take the ON clause of the join and </span><span class="cx"> # move it up to the WHERE clause of its parent select, and append (+) to all right-hand-side columns </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 15:03:19
|
<!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>[1348] sqlalchemy/trunk/test: fix to subquery parens</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1348</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-28 10:02:49 -0500 (Fri, 28 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>fix to subquery parens</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemysqlpy">sqlalchemy/trunk/lib/sqlalchemy/sql.py</a></li> <li><a href="#sqlalchemytrunktestselectpy">sqlalchemy/trunk/test/select.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemysqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/sql.py (1347 => 1348)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-28 01:37:29 UTC (rev 1347) +++ sqlalchemy/trunk/lib/sqlalchemy/sql.py 2006-04-28 15:02:49 UTC (rev 1348) </span><span class="lines">@@ -543,7 +543,6 @@ </span><span class="cx"> return BooleanExpression(self._compare_self(), null(), 'IS') </span><span class="cx"> else: </span><span class="cx"> obj = self._bind_param(obj) </span><del>- </del><span class="cx"> return BooleanExpression(self._compare_self(), obj, operator, type=self._compare_type(obj)) </span><span class="cx"> def _operate(self, operator, obj): </span><span class="cx"> if _is_literal(obj): </span><span class="lines">@@ -884,9 +883,9 @@ </span><span class="cx"> self.operator = operator </span><span class="cx"> self.type = sqltypes.to_instance(type) </span><span class="cx"> self.parens = False </span><del>- if isinstance(self.left, BinaryClause): </del><ins>+ if isinstance(self.left, BinaryClause) or isinstance(self.left, Selectable): </ins><span class="cx"> self.left.parens = True </span><del>- if isinstance(self.right, BinaryClause): </del><ins>+ if isinstance(self.right, BinaryClause) or isinstance(self.right, Selectable): </ins><span class="cx"> self.right.parens = True </span><span class="cx"> def copy_container(self): </span><span class="cx"> return BinaryClause(self.left.copy_container(), self.right.copy_container(), self.operator) </span></span></pre></div> <a id="sqlalchemytrunktestselectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/select.py (1347 => 1348)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/select.py 2006-04-28 01:37:29 UTC (rev 1347) +++ sqlalchemy/trunk/test/select.py 2006-04-28 15:02:49 UTC (rev 1348) </span><span class="lines">@@ -151,6 +151,7 @@ </span><span class="cx"> self.runtest( </span><span class="cx"> select([users, s.c.street], from_obj=[s]), </span><span class="cx"> """SELECT users.user_id, users.user_name, users.password, s.street FROM users, (SELECT addresses.street AS street FROM addresses WHERE addresses.user_id = users.user_id) AS s""") </span><ins>+ </ins><span class="cx"> </span><span class="cx"> def testcolumnsubquery(self): </span><span class="cx"> s = select([table1.c.myid], scalar=True, correlate=False) </span><span class="lines">@@ -623,6 +624,11 @@ </span><span class="cx"> u = update(table1, table1.c.name == 'jack', values = {table1.c.name : s}) </span><span class="cx"> self.runtest(u, "UPDATE mytable SET name=(SELECT myothertable.otherid, myothertable.othername FROM myothertable WHERE myothertable.otherid = mytable.myid) WHERE mytable.name = :mytable_name") </span><span class="cx"> </span><ins>+ # test a correlated WHERE clause + s = select([table2.c.othername], table2.c.otherid == 7) + u = update(table1, table1.c.name==s) + self.runtest(u, "UPDATE mytable SET myid=:myid, name=:name, description=:description WHERE mytable.name = (SELECT myothertable.othername FROM myothertable WHERE myothertable.otherid = :myothertable_otherid)") + </ins><span class="cx"> def testdelete(self): </span><span class="cx"> self.runtest(delete(table1, table1.c.myid == 7), "DELETE FROM mytable WHERE mytable.myid = :mytable_myid") </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 01:37:46
|
<!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>[1347] sqlalchemy/branches/schema/lib/sqlalchemy/orm: polymorphic, step 1</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1347</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-27 20:37:29 -0500 (Thu, 27 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>polymorphic, step 1</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorph2py">sqlalchemy/branches/schema/examples/polymorph/polymorph2.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormquerypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorph2py"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph2.py (1346 => 1347)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 00:04:54 UTC (rev 1346) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-28 01:37:29 UTC (rev 1347) </span><span class="lines">@@ -34,6 +34,9 @@ </span><span class="cx"> </span><span class="cx"> # create our classes. The Engineer and Manager classes extend from Person. </span><span class="cx"> class Person(object): </span><ins>+ def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Ordinary person %s" % self.name </span><span class="cx"> class Engineer(Person): </span><span class="lines">@@ -43,13 +46,12 @@ </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Manager %s, status %s, manager_name %s" % (self.name, self.status, self.manager_name) </span><span class="cx"> class Company(object): </span><ins>+ def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Company %s" % self.name </span><span class="cx"> </span><del>-# assign plain vanilla mappers -assign_mapper(Person, people) -assign_mapper(Engineer, engineers, inherits=Person.mapper) -assign_mapper(Manager, managers, inherits=Person.mapper) </del><span class="cx"> </span><span class="cx"> # create a union that represents both types of joins. we have to use </span><span class="cx"> # nulls to pad out the disparate columns. </span><span class="lines">@@ -74,60 +76,53 @@ </span><span class="cx"> ], </span><span class="cx"> people.c.person_id==engineers.c.person_id)).alias('pjoin') </span><span class="cx"> </span><del>-print [c for c in person_join.c] </del><ins>+ +mapper(Person, people) +mapper(Engineer, engineers, inherits=Person) +mapper(Manager, managers, inherits=Person) </ins><span class="cx"> </span><del>-# MapperExtension object. -class PersonLoader(MapperExtension): - def create_instance(self, mapper, row, imap, class_): - if row[person_join.c.type] =='engineer': - return Engineer() - elif row[person_join.c.type] =='manager': - return Manager() - else: - return Person() - - def populate_instance(self, mapper, session, instance, row, identitykey, imap, isnew): - if row[person_join.c.type] =='engineer': - Engineer.mapper.populate_instance(session, instance, row, identitykey, imap, isnew, frommapper=mapper) - return False - elif row[person_join.c.type] =='manager': - Manager.mapper.populate_instance(session, instance, row, identitykey, imap, isnew, frommapper=mapper) - return False - else: - return sqlalchemy.mapping.EXT_PASS </del><ins>+people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}, non_primary=True) </ins><span class="cx"> </span><del>-people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}) </del><span class="cx"> </span><del>-assign_mapper(Company, companies, properties={ - 'employees': relation(people_mapper, lazy=False, private=True) </del><ins>+ +mapper(Company, companies, properties={ + 'employees': relation(people_mapper, lazy=False, private=True, backref='company') </ins><span class="cx"> }) </span><span class="cx"> </span><ins>+session = create_session() </ins><span class="cx"> c = Company(name='company1') </span><span class="cx"> c.employees.append(Manager(name='pointy haired boss', status='AAB', manager_name='manager1')) </span><span class="cx"> c.employees.append(Engineer(name='dilbert', status='BBA', engineer_name='engineer1', primary_language='java')) </span><span class="cx"> c.employees.append(Engineer(name='wally', status='CGG', engineer_name='engineer2', primary_language='python')) </span><span class="cx"> c.employees.append(Manager(name='jsmith', status='ABA', manager_name='manager2')) </span><del>-objectstore.commit() </del><ins>+session.save(c) +session.flush() </ins><span class="cx"> </span><del>-objectstore.clear() </del><ins>+session.clear() </ins><span class="cx"> </span><del>-c = Company.get(1) </del><ins>+c = session.query(Company).get(1) </ins><span class="cx"> for e in c.employees: </span><del>- print e, e._instance_key </del><ins>+ print e, e._instance_key, e.company </ins><span class="cx"> </span><span class="cx"> print "\n" </span><span class="cx"> </span><del>-dilbert = Engineer.mapper.get_by(name='dilbert') </del><ins>+dilbert = session.query(people_mapper).get_by(name='dilbert') +print "DILBERT1", dilbert +dilbert2 = session.query(Engineer).get_by(name='dilbert') +print "DILBERT2", dilbert2 +assert dilbert is dilbert2 + </ins><span class="cx"> dilbert.engineer_name = 'hes dibert!' </span><del>-objectstore.commit() </del><span class="cx"> </span><del>-objectstore.clear() -c = Company.get(1) </del><ins>+session.flush() +session.clear() + +c = session.query(Company).get(1) </ins><span class="cx"> for e in c.employees: </span><span class="cx"> print e, e._instance_key </span><span class="cx"> </span><del>-objectstore.delete(c) -objectstore.commit() </del><ins>+session.delete(c) +session.flush() </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> managers.drop() </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1346 => 1347)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 00:04:54 UTC (rev 1346) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-28 01:37:29 UTC (rev 1347) </span><span class="lines">@@ -39,7 +39,6 @@ </span><span class="cx"> def __init__(self, </span><span class="cx"> class_, </span><span class="cx"> table, </span><del>- primarytable = None, </del><span class="cx"> properties = None, </span><span class="cx"> primary_key = None, </span><span class="cx"> is_primary = False, </span><span class="lines">@@ -51,11 +50,12 @@ </span><span class="cx"> allow_column_override = False, </span><span class="cx"> entity_name = None, </span><span class="cx"> always_refresh = False, </span><del>- version_id_col = None): </del><ins>+ version_id_col = None, + polymorphic_on=None, + polymorphic_map=None, + polymorphic_ident=None, + selectfrom=None): </ins><span class="cx"> </span><del>- if primarytable is not None: - sys.stderr.write("'primarytable' argument to mapper is deprecated\n") - </del><span class="cx"> ext = MapperExtension() </span><span class="cx"> </span><span class="cx"> for ext_class in global_extensions: </span><span class="lines">@@ -77,7 +77,9 @@ </span><span class="cx"> self.always_refresh = always_refresh </span><span class="cx"> self.version_id_col = version_id_col </span><span class="cx"> self._inheriting_mappers = sets.Set() </span><del>- </del><ins>+ self.polymorphic_on = polymorphic_on + self.polymorphic_map = polymorphic_map or {} + </ins><span class="cx"> if not issubclass(class_, object): </span><span class="cx"> raise ArgumentError("Class '%s' is not a new-style class" % class_.__name__) </span><span class="cx"> </span><span class="lines">@@ -91,7 +93,14 @@ </span><span class="cx"> else: </span><span class="cx"> self.table = table </span><span class="cx"> </span><ins>+ if selectfrom is None: + self.selectfrom = self.table + else: + self.selectfrom = selectfrom + </ins><span class="cx"> if inherits is not None: </span><ins>+ if isinstance(inherits, type): + inherits = class_mapper(inherits) </ins><span class="cx"> if self.class_.__mro__[1] != inherits.class_: </span><span class="cx"> raise ArgumentError("Class '%s' does not inherit from '%s'" % (self.class_.__name__, inherits.class_.__name__)) </span><span class="cx"> self.primarytable = inherits.primarytable </span><span class="lines">@@ -116,11 +125,15 @@ </span><span class="cx"> self._synchronizer = None </span><span class="cx"> self.inherits = inherits </span><span class="cx"> self.noninherited_table = table </span><ins>+ if polymorphic_ident is not None: + inherits.add_polymorphic_mapping(polymorphic_ident, self) </ins><span class="cx"> else: </span><span class="cx"> self.primarytable = self.table </span><span class="cx"> self.noninherited_table = self.table </span><span class="cx"> self._synchronizer = None </span><span class="cx"> self.inherits = None </span><ins>+ if polymorphic_ident is not None: + raise ArgumentError("'polymorphic_ident' argument can only be used with inherits=<somemapper>") </ins><span class="cx"> </span><span class="cx"> # locate all tables contained within the "table" passed in, which </span><span class="cx"> # may be a join or other construct </span><span class="lines">@@ -198,6 +211,10 @@ </span><span class="cx"> self._init_class() </span><span class="cx"> elif not non_primary: </span><span class="cx"> raise ArgumentError("Class '%s' already has a primary mapper defined. Use is_primary=True to assign a new primary mapper to the class, or use non_primary=True to create a non primary Mapper" % self.class_) </span><ins>+ + for key in self.polymorphic_map.keys(): + if isinstance(self.polymorphic_map[key], type): + self.polymorphic_map[key] = class_mapper(self.polymorphic_map[key]) </ins><span class="cx"> </span><span class="cx"> if inherits is not None: </span><span class="cx"> inherits._inheriting_mappers.add(self) </span><span class="lines">@@ -217,6 +234,11 @@ </span><span class="cx"> #for key, value in self.columntoproperty.iteritems(): </span><span class="cx"> # print key.table.name, key.key, [(v.key, v) for v in value] </span><span class="cx"> </span><ins>+ def add_polymorphic_mapping(self, key, class_or_mapper, entity_name=None): + if isinstance(class_or_mapper, type): + class_or_mapper = class_mapper(class_or_mapper, entity_name=entity_name) + self.polymorphic_map[key] = class_or_mapper + </ins><span class="cx"> def using(self, session): </span><span class="cx"> return querylib.Query(self, session=session) </span><span class="cx"> def query(self, session=None): </span><span class="lines">@@ -720,6 +742,15 @@ </span><span class="cx"> list. if the instance already exists in the given identity map, its not added. in </span><span class="cx"> either case, executes all the property loaders on the instance to also process extra </span><span class="cx"> information in the row.""" </span><ins>+ + if self.polymorphic_on is not None: + discriminator = row[self.polymorphic_on] + mapper = self.polymorphic_map[discriminator] + if mapper is not self: + row = self.translate_row(mapper, row) + return mapper._instance(session, row, imap, result=result, populate_existing=populate_existing) + + </ins><span class="cx"> # look in main identity map. if its there, we dont do anything to it, </span><span class="cx"> # including modifying any of its related items lists, as its already </span><span class="cx"> # been exposed to being modified by the application. </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py (1346 => 1347)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-28 00:04:54 UTC (rev 1346) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-28 01:37:29 UTC (rev 1347) </span><span class="lines">@@ -31,7 +31,7 @@ </span><span class="cx"> return sessionlib.get_session() </span><span class="cx"> else: </span><span class="cx"> return self._session </span><del>- table = property(lambda s:s.mapper.table) </del><ins>+ table = property(lambda s:s.mapper.selectfrom) </ins><span class="cx"> props = property(lambda s:s.mapper.props) </span><span class="cx"> session = property(_get_session) </span><span class="cx"> </span><span class="lines">@@ -203,7 +203,6 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> pass </span><span class="cx"> </span><del>- print "_GET!", key, ident </del><span class="cx"> if ident is None: </span><span class="cx"> ident = key[1] </span><span class="cx"> i = 0 </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-28 00:05:04
|
<!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>[1346] sqlalchemy/branches/schema/test: unittest placeholders</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1346</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-27 19:04:54 -0500 (Thu, 27 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>unittest placeholders</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemybranchesschematestpolymorphpy">sqlalchemy/branches/schema/test/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschematestsessionpy">sqlalchemy/branches/schema/test/session.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1345 => 1346)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-27 23:56:09 UTC (rev 1345) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-28 00:04:54 UTC (rev 1346) </span><span class="lines">@@ -165,10 +165,7 @@ </span><span class="cx"> if recursive is None: </span><span class="cx"> recursive = sets.Set() </span><span class="cx"> </span><del>- if self.uselist: - childlist = sessionlib.global_attributes.get_history(object, self.key, passive = False) - else: - childlist = sessionlib.global_attributes.get_history(object, self.key) </del><ins>+ childlist = sessionlib.global_attributes.get_history(object, self.key, passive=True) </ins><span class="cx"> </span><span class="cx"> for c in childlist.added_items() + childlist.deleted_items() + childlist.unchanged_items(): </span><span class="cx"> if c is not None: </span></span></pre></div> <a id="sqlalchemybranchesschematestpolymorphpy"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/test/polymorph.py (1345 => 1346)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/polymorph.py 2006-04-27 23:56:09 UTC (rev 1345) +++ sqlalchemy/branches/schema/test/polymorph.py 2006-04-28 00:04:54 UTC (rev 1346) </span><span class="lines">@@ -0,0 +1,5 @@ </span><ins>+# test basic polymorphic relationship with a single tasble + +# test polymorphic relationship with multiple tables + +# test that loading an object A from its non-polymorphic mapper returns the same identity as from its polymorphic mapper </ins><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemybranchesschematestsessionpy"></a> <div class="addfile"><h4>Added: sqlalchemy/branches/schema/test/session.py (1345 => 1346)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/session.py 2006-04-27 23:56:09 UTC (rev 1345) +++ sqlalchemy/branches/schema/test/session.py 2006-04-28 00:04:54 UTC (rev 1346) </span><span class="lines">@@ -0,0 +1,7 @@ </span><ins>+ +# test merging a composed object. + +# test that when cascading an operation, like "merge", lazy-loaded scalar and list attributes that werent already loaded on the given object remain not loaded. + +# test putting an object in session A, "moving" it to session B, insure its in B and not in A + </ins></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-27 23:56:22
|
<!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>[1345] sqlalchemy/trunk/test: the latest and greatest method to keep attributes from growing</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1345</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-27 18:56:09 -0500 (Thu, 27 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>the latest and greatest method to keep attributes from growing</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyattributespy">sqlalchemy/trunk/lib/sqlalchemy/attributes.py</a></li> <li><a href="#sqlalchemytrunktestattributespy">sqlalchemy/trunk/test/attributes.py</a></li> <li><a href="#sqlalchemytrunktestmassloadpy">sqlalchemy/trunk/test/massload.py</a></li> </ul> <h3>Added Paths</h3> <ul> <li><a href="#sqlalchemytrunktestmasscreate2py">sqlalchemy/trunk/test/masscreate2.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/attributes.py (1344 => 1345)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/attributes.py 2006-04-26 21:43:33 UTC (rev 1344) +++ sqlalchemy/trunk/lib/sqlalchemy/attributes.py 2006-04-27 23:56:09 UTC (rev 1345) </span><span class="lines">@@ -79,8 +79,12 @@ </span><span class="cx"> ManagedAttribute objects associated with the instance via this dictionary.""" </span><span class="cx"> def __init__(self, obj, key): </span><span class="cx"> self.__obj = weakref.ref(obj) </span><del>- #self.obj = obj </del><span class="cx"> self.key = key </span><ins>+ def __getstate__(self): + return {'key':self.key, 'obj':self.obj} + def __setstate__(self, d): + self.key = d['key'] + self.__obj = weakref.ref(d['obj']) </ins><span class="cx"> obj = property(lambda s:s.__obj()) </span><span class="cx"> def history(self, **kwargs): </span><span class="cx"> return self </span><span class="lines">@@ -496,25 +500,4 @@ </span><span class="cx"> will be passed along to newly created ManagedAttribute.""" </span><span class="cx"> if not hasattr(class_, '_attribute_manager'): </span><span class="cx"> class_._attribute_manager = self </span><del>- class_._managed_attributes = ObjectAttributeGateway() </del><span class="cx"> setattr(class_, key, self.create_prop(class_, key, uselist, callable_, **kwargs)) </span><del>- -managed_attributes = weakref.WeakKeyDictionary() - -class ObjectAttributeGateway(object): - """handles the dictionary of ManagedAttributes for instances. this level of indirection - is to prevent circular references upon objects, as well as keeping them Pickle-compatible.""" - def __set__(self, obj, value): - managed_attributes[obj] = value - def __delete__(self, obj): - try: - del managed_attributes[obj] - except KeyError: - raise AttributeError() - def __get__(self, obj, owner): - if obj is None: - return self - try: - return managed_attributes[obj] - except KeyError: - raise AttributeError() </del><span class="cx">\ No newline at end of file </span></span></pre></div> <a id="sqlalchemytrunktestattributespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/attributes.py (1344 => 1345)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/attributes.py 2006-04-26 21:43:33 UTC (rev 1344) +++ sqlalchemy/trunk/test/attributes.py 2006-04-27 23:56:09 UTC (rev 1345) </span><span class="lines">@@ -45,7 +45,8 @@ </span><span class="cx"> manager.register_attribute(MyTest, 'email_address', uselist = False) </span><span class="cx"> x = MyTest() </span><span class="cx"> x.user_id=7 </span><del>- pickle.dumps(x) </del><ins>+ s = pickle.dumps(x) + y = pickle.loads(s) </ins><span class="cx"> </span><span class="cx"> def testlist(self): </span><span class="cx"> class User(object):pass </span></span></pre></div> <a id="sqlalchemytrunktestmasscreate2py"></a> <div class="addfile"><h4>Added: sqlalchemy/trunk/test/masscreate2.py (1344 => 1345)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/masscreate2.py 2006-04-26 21:43:33 UTC (rev 1344) +++ sqlalchemy/trunk/test/masscreate2.py 2006-04-27 23:56:09 UTC (rev 1345) </span><span class="lines">@@ -0,0 +1,36 @@ </span><ins>+import gc + +import random, string + +from sqlalchemy.attributes import * + +# with this test, run top. make sure the Python process doenst grow in size arbitrarily. + +class User(object): + pass + +class Address(object): + pass + +attr_manager = AttributeManager() +attr_manager.register_attribute(User, 'id', uselist=False) +attr_manager.register_attribute(User, 'name', uselist=False) +attr_manager.register_attribute(User, 'addresses', uselist=True) +attr_manager.register_attribute(Address, 'email', uselist=False) +attr_manager.register_attribute(Address, 'user', uselist=False) + + +for i in xrange(1000): + for j in xrange(1000): + u = User() + u.name = str(random.randint(0, 100000000)) + for k in xrange(10): + a = Address() + a.email_address = str(random.randint(0, 100000000)) + u.addresses.append(a) + a.user = u + print "clearing" + #managed_attributes.clear() + gc.collect() + + </ins></span></pre></div> <a id="sqlalchemytrunktestmassloadpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/massload.py (1344 => 1345)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/massload.py 2006-04-26 21:43:33 UTC (rev 1344) +++ sqlalchemy/trunk/test/massload.py 2006-04-27 23:56:09 UTC (rev 1345) </span><span class="lines">@@ -56,7 +56,7 @@ </span><span class="cx"> a.value = 'changed...' </span><span class="cx"> assert len(objectstore.get_session().dirty) == len(l) </span><span class="cx"> assert len(objectstore.get_session().identity_map) == len(l) </span><del>- assert len(attributes.managed_attributes) == len(l) </del><ins>+ #assert len(attributes.managed_attributes) == len(l) </ins><span class="cx"> print len(objectstore.get_session().dirty) </span><span class="cx"> print len(objectstore.get_session().identity_map) </span><span class="cx"> objectstore.expunge(*l) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 21:43:44
|
<!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>[1344] sqlalchemy/trunk/lib/sqlalchemy: commented out default schema name check</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1344</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-26 16:43:33 -0500 (Wed, 26 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>commented out default schema name check</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemymappingpropertiespy">sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py</a></li> <li><a href="#sqlalchemytrunklibsqlalchemyschemapy">sqlalchemy/trunk/lib/sqlalchemy/schema.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemymappingpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py (1343 => 1344)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-04-26 18:24:17 UTC (rev 1343) +++ sqlalchemy/trunk/lib/sqlalchemy/mapping/properties.py 2006-04-26 21:43:33 UTC (rev 1344) </span><span class="lines">@@ -671,7 +671,7 @@ </span><span class="cx"> lazywhere = primaryjoin.copy_container() </span><span class="cx"> li = BinaryVisitor(visit_binary) </span><span class="cx"> lazywhere.accept_visitor(li) </span><del>- print "PRIMARYJOIN", str(lazywhere), [b.key for b in binds.values()] </del><ins>+ #print "PRIMARYJOIN", str(lazywhere), [b.key for b in binds.values()] </ins><span class="cx"> if secondaryjoin is not None: </span><span class="cx"> lazywhere = sql.and_(lazywhere, secondaryjoin) </span><span class="cx"> return (lazywhere, binds, reverselookup) </span></span></pre></div> <a id="sqlalchemytrunklibsqlalchemyschemapy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/schema.py (1343 => 1344)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-04-26 18:24:17 UTC (rev 1343) +++ sqlalchemy/trunk/lib/sqlalchemy/schema.py 2006-04-26 21:43:33 UTC (rev 1344) </span><span class="lines">@@ -58,7 +58,7 @@ </span><span class="cx"> engine = property(_get_engine) </span><span class="cx"> </span><span class="cx"> def _get_table_key(engine, name, schema): </span><del>- if schema is not None and schema == engine.get_default_schema_name(): </del><ins>+ if schema is not None:# and schema == engine.get_default_schema_name(): </ins><span class="cx"> schema = None </span><span class="cx"> if schema is None: </span><span class="cx"> return name </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 18:24:30
|
<!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>[1343] sqlalchemy/branches/schema: improvements to polymorphic mapping and supporting fixes in properties/backrefs.</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1343</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-26 13:24:17 -0500 (Wed, 26 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>improvements to polymorphic mapping and supporting fixes in properties/backrefs. getting ready to add polymorphic behavior to the core. also fixed [ticket:154] pending further testing. updated CHANGES with the general things happening in 0.2 as well as affected tickets</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemaCHANGES">sqlalchemy/branches/schema/CHANGES</a></li> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorphpy">sqlalchemy/branches/schema/examples/polymorph/polymorph.py</a></li> <li><a href="#sqlalchemybranchesschemaexamplespolymorphpolymorph2py">sqlalchemy/branches/schema/examples/polymorph/polymorph2.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyansisqlpy">sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyengineurlpy">sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormquerypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py</a></li> <li><a href="#sqlalchemybranchesschematestparseconnectpy">sqlalchemy/branches/schema/test/parseconnect.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemaCHANGES"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/CHANGES (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/CHANGES 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/CHANGES 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -1,5 +1,53 @@ </span><del>-next -- some fixes to topological sort algorithm </del><ins>+0.2 +- overhaul to Engine system so that what was formerly the SQLEngine +is now a ComposedSQLEngine which consists of a variety of components, +including a Dialect, ConnectionProvider, etc. This impacted all the +db modules as well as Session and Mapper. +- create_engine now takes only RFC-1738-style strings: +driver://user:password@host:port/database +- total rewrite of connection-scoping methodology, Connection objects +can now execute clause elements directly, added explicit "close" as +well as support throughout Engine/ORM to handle closing properly, +no longer relying upon __del__ internally to return connections +to the pool [ticket:152]. +- overhaul to Session interface and scoping. uses hibernate-style +methods, including query(class), save(), save_or_update(), etc. +no threadlocal scope is installed by default. Provides a binding +interface to specific Engines and/or Connections so that underlying +Schema objects do not need to be bound to an Engine. Added a basic +SessionTransaction object that can simplistically aggregate transactions +across multiple engines. +- overhaul to mapper's dependency and "cascade" behavior; dependency logic +factored out of properties.py into a separate module "dependency.py". +"cascade" behavior is now explicitly controllable, proper implementation +of "delete", "delete-orphan", etc. dependency system can now determine at +flush time if a child object has a parent or not so that it makes better +decisions on how that child should be updated in the DB with regards to deletes. +- overhaul to Schema to build upon MetaData object instead of an Engine. +Entire SQL/Schema system can be used with no Engines whatsoever, executed +solely by an explicit Connection object. the "bound" methodlogy exists via the +BoundMetaData for schema objects. ProxyEngine is generally not needed +anymore and is replaced by DynamicMetaData. +- "oid" system has been totally moved into compile-time behavior; +if they are used in an order_by where they are not available, the order_by +doesnt get compiled, fixes [ticket:147] +- overhaul to packaging; "mapping" is now "orm", "objectstore" is now +"session", the old "objectstore" namespace gets loaded in via the +"threadlocal" mod if used +- mods now called in via "import <modname>". extensions favored over +mods as mods are globally-monkeypatching +- fix to add_property so that it propigates properties to inheriting +mappers [ticket:154] +- backrefs create themselves against primary mapper of its originating +property, priamry/secondary join arguments can be specified to override. +helps their usage with polymorphic mappers +- "table exists" function has been implemented [ticket:31] +- "create_all/drop_all" added to MetaData object [ticket:98] +- improvements and fixes to topological sort algorithm, as well as more +unit tests +- tutorial page added to docs which also can be run with a custom doctest +runner to insure its properly working. docs generally overhauled to +deal with new code patterns </ins><span class="cx"> </span><span class="cx"> 0.1.6 </span><span class="cx"> - support for MS-SQL added courtesy Rick Morrison, Runar Petursson </span></span></pre></div> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorphpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -32,6 +32,9 @@ </span><span class="cx"> </span><span class="cx"> # create our classes. The Engineer and Manager classes extend from Person. </span><span class="cx"> class Person(object): </span><ins>+ def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Ordinary person %s" % self.name </span><span class="cx"> class Engineer(Person): </span><span class="lines">@@ -41,6 +44,9 @@ </span><span class="cx"> def __repr__(self): </span><span class="cx"> return "Manager %s, description %s" % (self.name, self.description) </span><span class="cx"> class Company(object): </span><ins>+ def __init__(self, **kwargs): + for key, value in kwargs.iteritems(): + setattr(self, key, value) </ins><span class="cx"> def __repr__(self): </span><span class="cx"> return "Company %s" % self.name </span><span class="cx"> </span><span class="lines">@@ -48,9 +54,9 @@ </span><span class="cx"> # creating for these classes, they automatically become the "primary mappers", which </span><span class="cx"> # define the dependency relationships between the classes, so we do a straight </span><span class="cx"> # inheritance setup, i.e. no modifications to how objects are loaded or anything like that. </span><del>-assign_mapper(Person, people) -assign_mapper(Engineer, engineers, inherits=Person.mapper) -assign_mapper(Manager, managers, inherits=Person.mapper) </del><ins>+mapper(Person, people) +mapper(Engineer, engineers, inherits=class_mapper(Person)) +mapper(Manager, managers, inherits=class_mapper(Person)) </ins><span class="cx"> </span><span class="cx"> # next, we define a query that is going to load Managers and Engineers in one shot. </span><span class="cx"> # we will use a UNION ALL with an extra hardcoded column to indicate the type of object. </span><span class="lines">@@ -81,7 +87,7 @@ </span><span class="cx"> </span><span class="cx"> # MapperExtension object. </span><span class="cx"> class PersonLoader(MapperExtension): </span><del>- def create_instance(self, mapper, row, imap, class_): </del><ins>+ def create_instance(self, session, mapper, row, imap, class_): </ins><span class="cx"> if row['pjoin_type'] =='engineer': </span><span class="cx"> e = Engineer() </span><span class="cx"> e.special_description = row['pjoin_description'] </span><span class="lines">@@ -94,8 +100,11 @@ </span><span class="cx"> </span><span class="cx"> # set up the polymorphic mapper, which maps the person_join we set up to </span><span class="cx"> # the Person class, using an instance of PersonLoader. </span><del>-people_mapper = mapper(Person, person_join, extension=ext) </del><ins>+people_mapper = mapper(Person, person_join, extension=ext, non_primary=True) </ins><span class="cx"> </span><ins>+# TODO: polymorphic options, i.e.: +# people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}) + </ins><span class="cx"> # create a mapper for Company. the 'employees' relationship points to </span><span class="cx"> # our new people_mapper. </span><span class="cx"> # </span><span class="lines">@@ -107,36 +116,38 @@ </span><span class="cx"> # themselves as dependent on the Person mapper's save operations. </span><span class="cx"> # (translation: it'll work) </span><span class="cx"> # TODO: get the eager loading to work (the compound select alias doesnt like being aliased itself) </span><del>-assign_mapper(Company, companies, properties={ - 'employees': relation(people_mapper, lazy=False, private=True) </del><ins>+mapper(Company, companies, properties={ + 'employees': relation(people_mapper, lazy=False, cascade="save-update,delete,delete-orphan", backref=backref("company")) </ins><span class="cx"> }) </span><span class="cx"> </span><ins>+session = create_session() </ins><span class="cx"> c = Company(name='company1') </span><span class="cx"> c.employees.append(Manager(name='pointy haired boss', description='manager1')) </span><span class="cx"> c.employees.append(Engineer(name='dilbert', special_description='engineer1')) </span><span class="cx"> c.employees.append(Engineer(name='wally', special_description='engineer2')) </span><span class="cx"> c.employees.append(Manager(name='jsmith', description='manager2')) </span><del>-objectstore.commit() </del><ins>+session.save(c) +session.flush() </ins><span class="cx"> </span><del>-objectstore.clear() </del><ins>+session.clear() </ins><span class="cx"> </span><del>-c = Company.get(1) </del><ins>+c = session.query(Company).get(1) </ins><span class="cx"> for e in c.employees: </span><span class="cx"> print e, e._instance_key </span><span class="cx"> </span><span class="cx"> print "\n" </span><span class="cx"> </span><del>-dilbert = Engineer.mapper.get_by(name='dilbert') </del><ins>+dilbert = session.query(Engineer).get_by(name='dilbert') </ins><span class="cx"> dilbert.special_description = 'hes dibert!' </span><del>-objectstore.commit() </del><ins>+session.flush() </ins><span class="cx"> </span><del>-objectstore.clear() -c = Company.get(1) </del><ins>+session.clear() +c = session.query(Company).get(1) </ins><span class="cx"> for e in c.employees: </span><del>- print e, e._instance_key </del><ins>+ print e, e._instance_key, e.company </ins><span class="cx"> </span><del>-objectstore.delete(c) -objectstore.commit() </del><ins>+session.delete(c) +session.flush() </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> managers.drop() </span></span></pre></div> <a id="sqlalchemybranchesschemaexamplespolymorphpolymorph2py"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/examples/polymorph/polymorph2.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/examples/polymorph/polymorph2.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -96,7 +96,7 @@ </span><span class="cx"> else: </span><span class="cx"> return sqlalchemy.mapping.EXT_PASS </span><span class="cx"> </span><del>-people_mapper = mapper(Person, person_join, extension=PersonLoader()) </del><ins>+people_mapper = mapper(Person, person_join, polymorphic_on=person_join.c.type, polymorphic_map={'engineer':Engineer, 'manager':Manager}) </ins><span class="cx"> </span><span class="cx"> assign_mapper(Company, companies, properties={ </span><span class="cx"> 'employees': relation(people_mapper, lazy=False, private=True) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/lib/sqlalchemy/ansisql.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -15,8 +15,8 @@ </span><span class="cx"> 'CURRENT_TIME', </span><span class="cx"> 'CURRENT_TIMESTAMP', </span><span class="cx"> 'CURRENT_DATE', </span><del>-'LOCAL_TIME', -'LOCAL_TIMESTAMP', </del><ins>+'LOCALTIME', +'LOCALTIMESTAMP', </ins><span class="cx"> 'CURRENT_USER', </span><span class="cx"> 'SESSION_USER', </span><span class="cx"> 'USER' </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyengineurlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/lib/sqlalchemy/engine/url.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -9,6 +9,8 @@ </span><span class="cx"> self.host = host </span><span class="cx"> self.port = port </span><span class="cx"> self.database= database </span><ins>+ def __str__(self): + return "%s:%s@%s:%s/%s" % (self.username,self.password, self.host,self.port,self.database) </ins><span class="cx"> def get_module(self): </span><span class="cx"> return getattr(__import__('sqlalchemy.databases.%s' % self.drivername).databases, self.drivername) </span><span class="cx"> def translate_connect_args(self, names): </span><span class="lines">@@ -43,13 +45,13 @@ </span><span class="cx"> (?: </span><span class="cx"> ([^/:]*) </span><span class="cx"> (?::([^/]*))? </span><del>- ) </del><ins>+ )? </ins><span class="cx"> (?:/(.*))? </span><span class="cx"> ''' </span><span class="cx"> , re.X) </span><span class="cx"> </span><span class="cx"> m = pattern.match(name) </span><del>- if m is not None and (m.group(4) or m.group(6)): </del><ins>+ if m is not None: </ins><span class="cx"> (name, username, password, host, port, database) = m.group(1, 2, 3, 4, 5, 6) </span><span class="cx"> opts = {'username':username,'password':password,'host':host,'port':port,'database':database} </span><span class="cx"> return URL(name, **opts) </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -76,6 +76,7 @@ </span><span class="cx"> self._options = {} </span><span class="cx"> self.always_refresh = always_refresh </span><span class="cx"> self.version_id_col = version_id_col </span><ins>+ self._inheriting_mappers = sets.Set() </ins><span class="cx"> </span><span class="cx"> if not issubclass(class_, object): </span><span class="cx"> raise ArgumentError("Class '%s' is not a new-style class" % class_.__name__) </span><span class="lines">@@ -199,6 +200,7 @@ </span><span class="cx"> raise ArgumentError("Class '%s' already has a primary mapper defined. Use is_primary=True to assign a new primary mapper to the class, or use non_primary=True to create a non primary Mapper" % self.class_) </span><span class="cx"> </span><span class="cx"> if inherits is not None: </span><ins>+ inherits._inheriting_mappers.add(self) </ins><span class="cx"> for key, prop in inherits.props.iteritems(): </span><span class="cx"> if not self.props.has_key(key): </span><span class="cx"> self.props[key] = prop.copy() </span><span class="lines">@@ -319,6 +321,11 @@ </span><span class="cx"> </span><span class="cx"> if init: </span><span class="cx"> prop.init(key, self) </span><ins>+ + for mapper in self._inheriting_mappers: + p = prop.copy() + p.parent = mapper + mapper.add_property(key, p, init=False) </ins><span class="cx"> </span><span class="cx"> def __str__(self): </span><span class="cx"> return "Mapper|" + self.class_.__name__ + "|" + (self.entity_name is not None and "/%s" % self.entity_name or "") + self.primarytable.name </span><span class="lines">@@ -332,7 +339,7 @@ </span><span class="cx"> return mapper_registry[self.class_key] </span><span class="cx"> </span><span class="cx"> def is_assigned(self, instance): </span><del>- """returns True if this mapper is the primary mapper for the given instance. this is dependent </del><ins>+ """returns True if this mapper handles the given instance. this is dependent </ins><span class="cx"> not only on class assignment but the optional "entity_name" parameter as well.""" </span><span class="cx"> return instance.__class__ is self.class_ and getattr(instance, '_entity_name', None) == self.entity_name </span><span class="cx"> </span><span class="lines">@@ -485,7 +492,10 @@ </span><span class="cx"> </span><span class="cx"> def _setattrbycolumn(self, obj, column, value): </span><span class="cx"> self.columntoproperty[column.original][0].setattr(obj, value) </span><del>- </del><ins>+ + def primary_mapper(self): + return mapper_registry[self.class_key] + </ins><span class="cx"> def save_obj(self, objects, uow, postupdate=False): </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></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -375,13 +375,16 @@ </span><span class="cx"> def lazyload(): </span><span class="cx"> params = {} </span><span class="cx"> allparams = True </span><del>- session = sessionlib.get_session(instance) - #print "setting up loader, lazywhere", str(self.lazywhere) - for col, bind in self.lazybinds.iteritems(): - params[bind.key] = self.parent._getattrbycolumn(instance, col) - if params[bind.key] is None: - allparams = False - break </del><ins>+ session = sessionlib.get_session(instance, raiseerror=False) + #print "setting up loader, lazywhere", str(self.lazywhere), "binds", self.lazybinds + if session is not None: + for col, bind in self.lazybinds.iteritems(): + params[bind.key] = self.parent._getattrbycolumn(instance, col) + if params[bind.key] is None: + allparams = False + break + else: + allparams = False </ins><span class="cx"> if allparams: </span><span class="cx"> # if we have a simple straight-primary key load, use mapper.get() </span><span class="cx"> # to possibly save a DB round trip </span><span class="lines">@@ -656,25 +659,35 @@ </span><span class="cx"> """called by the owning PropertyLoader to set up a backreference on the </span><span class="cx"> PropertyLoader's mapper.""" </span><span class="cx"> # try to set a LazyLoader on our mapper referencing the parent mapper </span><ins>+ mapper = prop.mapper.primary_mapper() </ins><span class="cx"> if not prop.mapper.props.has_key(self.key): </span><del>- if prop.secondaryjoin is not None: - # if setting up a backref to a many-to-many, reverse the order - # of the "primary" and "secondary" joins - pj = prop.secondaryjoin - sj = prop.primaryjoin - else: - pj = prop.primaryjoin - sj = None </del><ins>+ pj = self.kwargs.pop('primaryjoin', None) + sj = self.kwargs.pop('secondaryjoin', None) + # TODO: we are going to have the newly backref'd property create its + # primary/secondary join through normal means, and only override if they are + # specified to the constructor. think about if this is really going to work + # all the way. + #if pj is None: + # if prop.secondaryjoin is not None: + # # if setting up a backref to a many-to-many, reverse the order + # # of the "primary" and "secondary" joins + # pj = prop.secondaryjoin + # sj = prop.primaryjoin + # else: + # pj = prop.primaryjoin + # sj = None </ins><span class="cx"> lazy = self.kwargs.pop('lazy', True) </span><span class="cx"> if lazy: </span><span class="cx"> cls = LazyLoader </span><span class="cx"> else: </span><span class="cx"> cls = EagerLoader </span><del>- relation = cls(prop.parent, prop.secondary, pj, sj, backref=prop.key, is_backref=True, **self.kwargs) - prop.mapper.add_property(self.key, relation); </del><ins>+ # the backref property is set on the primary mapper + parent = prop.parent.primary_mapper() + relation = cls(parent, prop.secondary, pj, sj, backref=prop.key, is_backref=True, **self.kwargs) + mapper.add_property(self.key, relation); </ins><span class="cx"> else: </span><span class="cx"> # else set one of us as the "backreference" </span><del>- if not prop.mapper.props[self.key].is_backref: </del><ins>+ if not mapper.props[self.key].is_backref: </ins><span class="cx"> prop.is_backref=True </span><span class="cx"> prop._dependency_processor.is_backref=True </span><span class="cx"> def get_extension(self): </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -40,7 +40,7 @@ </span><span class="cx"> if not found. The *ident argument is a </span><span class="cx"> list of primary key columns in the order of the table def's primary key columns.""" </span><span class="cx"> key = self.mapper.identity_key(*ident) </span><del>- #print "key: " + repr(key) + " ident: " + repr(ident) </del><ins>+ print "key: " + repr(key) + " ident: " + repr(ident) </ins><span class="cx"> return self._get(key, ident, **kwargs) </span><span class="cx"> </span><span class="cx"> def get_by(self, *args, **params): </span><span class="lines">@@ -203,6 +203,7 @@ </span><span class="cx"> except KeyError: </span><span class="cx"> pass </span><span class="cx"> </span><ins>+ print "_GET!", key, ident </ins><span class="cx"> if ident is None: </span><span class="cx"> ident = key[1] </span><span class="cx"> i = 0 </span></span></pre></div> <a id="sqlalchemybranchesschematestparseconnectpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/test/parseconnect.py (1342 => 1343)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/test/parseconnect.py 2006-04-26 14:55:05 UTC (rev 1342) +++ sqlalchemy/branches/schema/test/parseconnect.py 2006-04-26 18:24:17 UTC (rev 1343) </span><span class="lines">@@ -1,10 +1,10 @@ </span><span class="cx"> from testbase import PersistTest </span><del>-import sqlalchemy.engine.strategies as strategies </del><ins>+import sqlalchemy.engine.url as url </ins><span class="cx"> import unittest </span><span class="cx"> </span><span class="cx"> class ParseConnectTest(PersistTest): </span><span class="cx"> def testrfc1738(self): </span><del>- for url in ( </del><ins>+ for text in ( </ins><span class="cx"> 'dbtype://username:password@hostspec:110//usr/db_file.db', </span><span class="cx"> 'dbtype://username:password@hostspec/database', </span><span class="cx"> 'dbtype://username:password@hostspec', </span><span class="lines">@@ -14,21 +14,13 @@ </span><span class="cx"> 'dbtype://hostspec/database', </span><span class="cx"> 'dbtype://hostspec', </span><span class="cx"> 'dbtype:///database', </span><del>- 'dbtype:///:memory:' </del><ins>+ 'dbtype:///:memory:', + 'dbtype://' </ins><span class="cx"> ): </span><del>- (name, opts) = strategies._parse_rfc1738_args(url, {}) </del><ins>+ u = url.make_url(text) </ins><span class="cx"> # TODO: assertion conditions </span><del>- print name, opts </del><ins>+ print u </ins><span class="cx"> </span><del>- def testurl(self): - for url in ( - 'dbtype://username=user&password=pw&host=host&port=1234&db=foo', - ): - #foo = strategies._parse_rfc1738_args(url, {}) - #assert foo is None - (name, opts) = strategies._parse_keyvalue_args(url, {}) - # TODO: assertion conditions - print name, opts </del><span class="cx"> </span><span class="cx"> if __name__ == "__main__": </span><span class="cx"> unittest.main() </span></span></pre> </div> </div> </body> </html> |
<!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>[1342] sqlalchemy/trunk/lib/sqlalchemy/ansisql.py: localtime/localtimestamp dont seem to need the underscore for postgres/mysql, making that default</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1342</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-26 09:55:05 -0500 (Wed, 26 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>localtime/localtimestamp dont seem to need the underscore for postgres/mysql, making that default</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunklibsqlalchemyansisqlpy">sqlalchemy/trunk/lib/sqlalchemy/ansisql.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunklibsqlalchemyansisqlpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/lib/sqlalchemy/ansisql.py (1341 => 1342)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-04-26 00:45:24 UTC (rev 1341) +++ sqlalchemy/trunk/lib/sqlalchemy/ansisql.py 2006-04-26 14:55:05 UTC (rev 1342) </span><span class="lines">@@ -19,8 +19,8 @@ </span><span class="cx"> 'CURRENT_TIME', </span><span class="cx"> 'CURRENT_TIMESTAMP', </span><span class="cx"> 'CURRENT_DATE', </span><del>-'LOCAL_TIME', -'LOCAL_TIMESTAMP', </del><ins>+'LOCALTIME', +'LOCALTIMESTAMP', </ins><span class="cx"> 'CURRENT_USER', </span><span class="cx"> 'SESSION_USER', </span><span class="cx"> 'USER' </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 00:45:34
|
<!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>[1341] sqlalchemy/trunk/test/mapper.py: added unittest to verify eager loads refresh expired instances</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1341</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-25 19:45:24 -0500 (Tue, 25 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>added unittest to verify eager loads refresh expired instances</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemytrunktestmapperpy">sqlalchemy/trunk/test/mapper.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemytrunktestmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/trunk/test/mapper.py (1340 => 1341)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/trunk/test/mapper.py 2006-04-26 00:08:05 UTC (rev 1340) +++ sqlalchemy/trunk/test/mapper.py 2006-04-26 00:45:24 UTC (rev 1341) </span><span class="lines">@@ -124,6 +124,20 @@ </span><span class="cx"> objectstore.refresh(u) </span><span class="cx"> self.assert_sql_count(db, go, 1) </span><span class="cx"> </span><ins>+ def testexpire_eager(self): + """tests that an eager load will populate expire()'d objects""" + m = mapper(User, users, properties={'addresses':relation(mapper(Address, addresses))}) + [u1, u2, u3] = m.select(users.c.user_id.in_(7, 8, 9)) + self.echo([repr(x.addresses) for x in [u1, u2, u3]]) + [objectstore.expire(u) for u in [u1, u2, u3]] + m2 = m.options(eagerload('addresses')) + l = m2.select(users.c.user_id.in_(7,8,9)) + def go(): + u1.addresses + u2.addresses + u3.addresses + self.assert_sql_count(db, go, 0) + </ins><span class="cx"> def testsessionpropigation(self): </span><span class="cx"> sess = objectstore.Session() </span><span class="cx"> m = mapper(User, users, properties={'addresses':relation(mapper(Address, addresses), lazy=True)}) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 00:08:19
|
<!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>[1340] zblog/trunk/lib/zblog/controller/__init__.py: dev</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1340</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-25 19:08:05 -0500 (Tue, 25 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>dev</pre> <h3>Modified Paths</h3> <ul> <li><a href="#zblogtrunklibzblogcontroller__init__py">zblog/trunk/lib/zblog/controller/__init__.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="zblogtrunklibzblogcontroller__init__py"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/__init__.py (1339 => 1340)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/__init__.py 2006-04-26 00:06:04 UTC (rev 1339) +++ zblog/trunk/lib/zblog/controller/__init__.py 2006-04-26 00:08:05 UTC (rev 1340) </span><span class="lines">@@ -11,7 +11,7 @@ </span><span class="cx"> s = m.get_session() </span><span class="cx"> u = s.get('user', None) </span><span class="cx"> if u is not None: </span><del>- return zblog.database.mappers.session().merge(u) </del><ins>+ return self.sqlsess.merge(u) </ins><span class="cx"> else: </span><span class="cx"> return None </span><span class="cx"> sqlsess = property(lambda s:zblog.database.mappers.session()) </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 00:06:17
|
<!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>[1339] zblog/trunk/components: more literal Session usage</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1339</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-25 19:06:04 -0500 (Tue, 25 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>more literal Session usage</pre> <h3>Modified Paths</h3> <ul> <li><a href="#zblogtrunkcomponentsdatamyc">zblog/trunk/components/data.myc</a></li> <li><a href="#zblogtrunklibzblogcontroller__init__py">zblog/trunk/lib/zblog/controller/__init__.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerblogcommentspy">zblog/trunk/lib/zblog/controller/blog/comments.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerblogindexpy">zblog/trunk/lib/zblog/controller/blog/index.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerloginpy">zblog/trunk/lib/zblog/controller/login.py</a></li> <li><a href="#zblogtrunklibzblogcontrollermanageblogpy">zblog/trunk/lib/zblog/controller/manage/blog.py</a></li> <li><a href="#zblogtrunklibzblogcontrollermanageuserpy">zblog/trunk/lib/zblog/controller/manage/user.py</a></li> <li><a href="#zblogtrunklibzblogdatabasemapperspy">zblog/trunk/lib/zblog/database/mappers.py</a></li> <li><a href="#zblogtrunklibzblogdomainactionspy">zblog/trunk/lib/zblog/domain/actions.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="zblogtrunkcomponentsdatamyc"></a> <div class="modfile"><h4>Modified: zblog/trunk/components/data.myc (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/components/data.myc 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/components/data.myc 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -5,7 +5,7 @@ </span><span class="cx"> </span><span class="cx"> <%global> </span><span class="cx"> from zblog.domain.blog import * </span><del>- from zblog.database.mappers import query </del><ins>+ from zblog.database.mappers import session </ins><span class="cx"> </%global> </span><span class="cx"> </span><span class="cx"> <%method bloglist> </span><span class="lines">@@ -15,9 +15,9 @@ </span><span class="cx"> </%args> </span><span class="cx"> <%init> </span><span class="cx"> if user is not None: </span><del>- blogs = query(Blog).select_by(owner_id=user.id) </del><ins>+ blogs = session().query(Blog).select_by(owner_id=user.id) </ins><span class="cx"> else: </span><del>- blogs = query(Blog).select() </del><ins>+ blogs = session().query(Blog).select() </ins><span class="cx"> if not m.has_content(): </span><span class="cx"> return blogs </span><span class="cx"> </%init> </span><span class="lines">@@ -44,7 +44,7 @@ </span><span class="cx"> keyword=False </span><span class="cx"> </%args> </span><span class="cx"> <%init> </span><del>- posts = query(Post).select_by(blog_id=blog.id, keyword=keyword) </del><ins>+ posts = session().query(Post).select_by(blog_id=blog.id, keyword=keyword) </ins><span class="cx"> if not m.has_content(): </span><span class="cx"> return posts </span><span class="cx"> </%init> </span></span></pre></div> <a id="zblogtrunklibzblogcontroller__init__py"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/__init__.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/__init__.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/__init__.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -14,7 +14,7 @@ </span><span class="cx"> return zblog.database.mappers.session().merge(u) </span><span class="cx"> else: </span><span class="cx"> return None </span><del>- </del><ins>+ sqlsess = property(lambda s:zblog.database.mappers.session()) </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerblogcommentspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/blog/comments.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/blog/comments.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/blog/comments.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -3,7 +3,6 @@ </span><span class="cx"> from zblog.domain.blog import * </span><span class="cx"> import zblog.domain.actions as actions </span><span class="cx"> import zblog.util.form as formutil </span><del>-import zblog.database.mappers as mapper </del><span class="cx"> </span><span class="cx"> class Comments(Controller): </span><span class="cx"> @access_control() </span><span class="lines">@@ -15,7 +14,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -31,7 +30,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- comment = mapper.query(Comment).get(comment_id) </del><ins>+ comment = self.sqlsess.query(Comment).get(comment_id) </ins><span class="cx"> if comment is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -41,12 +40,12 @@ </span><span class="cx"> @access_control(action=actions.CreateComment()) </span><span class="cx"> def post(self, m, ARGS, post_id, parent_comment_id, confirm=False, preview=False): </span><span class="cx"> """posts a comment, or provides a preview display.""" </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="cx"> if parent_comment_id: </span><del>- parentcomment = mapper.query(Comment).get(parent_comment_id) </del><ins>+ parentcomment = self.sqlsess.query(Comment).get(parent_comment_id) </ins><span class="cx"> else: </span><span class="cx"> parentcomment = None </span><span class="cx"> form = self.commentform(m, ARGS, post, comment=parentcomment) </span><span class="lines">@@ -59,8 +58,8 @@ </span><span class="cx"> self.template(m, '/blog/postcomment.myt', post=post, form=form, comment=parentcomment, preview=comment) </span><span class="cx"> return </span><span class="cx"> comment = self.createcomment(m, post, form, parentcomment) </span><del>- mapper.session().save(comment) - mapper.flush() </del><ins>+ self.sqlsess.save(comment) + self.sqlsess.flush() </ins><span class="cx"> form = self.commentform(m, ARGS, post, comment) </span><span class="cx"> form.append_success("Comment posted!") </span><span class="cx"> self.template(m, '/blog/postcomment.myt', post=post, comment=comment, form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerblogindexpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/blog/index.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/blog/index.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/blog/index.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -3,7 +3,6 @@ </span><span class="cx"> from zblog.domain.blog import * </span><span class="cx"> import zblog.domain.actions as actions </span><span class="cx"> import zblog.util.form as formutil </span><del>-import zblog.database.mappers as mapper </del><span class="cx"> from zblog.controller.blog.comments import index as commentcontroller </span><span class="cx"> </span><span class="cx"> class BlogHome(Controller): </span><span class="lines">@@ -20,7 +19,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -29,12 +28,12 @@ </span><span class="cx"> @access_control(action=actions.CreatePost()) </span><span class="cx"> def post(self, m, ARGS, blog_id, post_id=None, preview=False): </span><span class="cx"> """submits a post, or previews it.""" </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> form.set_request(ARGS, validate=True) </span><span class="cx"> </span><span class="cx"> if post_id: </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> form.append_error("no post found for id '%s'" % post_id) </span><span class="cx"> self.template(m, '/blog/index.myt', blog=blog, loadcomponent='/blog/forms.myt:postform', form=form) </span><span class="lines">@@ -52,12 +51,11 @@ </span><span class="cx"> self.reflect_to(m, form, preview, blog) </span><span class="cx"> self.template(m, '/blog/index.myt', blog=blog, loadcomponent='/blog/forms.myt:postform', form=form, preview=preview, post=post) </span><span class="cx"> else: </span><del>- sess = mapper.session() </del><span class="cx"> if post is None: </span><span class="cx"> post = Post() </span><del>- sess.save(post) </del><ins>+ self.sqlsess.save(post) </ins><span class="cx"> self.reflect_to(m, form, post, blog) </span><del>- mapper.flush() </del><ins>+ self.sqlsess.flush() </ins><span class="cx"> if not post_id: </span><span class="cx"> form.append_success("Post added") </span><span class="cx"> else: </span><span class="lines">@@ -72,10 +70,10 @@ </span><span class="cx"> for keyword in form['topic_keywords'].value.split(' '): </span><span class="cx"> if not keyword: </span><span class="cx"> continue </span><del>- topic = mapper.query(Topic).get_by(keyword=keyword) </del><ins>+ topic = self.sqlsess.query(Topic).get_by(keyword=keyword) </ins><span class="cx"> if topic is None: </span><span class="cx"> topic = Topic(keyword=keyword, description=keyword) </span><del>- mapper.session().save(topic) </del><ins>+ self.sqlsess.save(topic) </ins><span class="cx"> post.topics.append(TopicAssociation(post=post, topic=topic, is_primary=False)) </span><span class="cx"> </span><span class="cx"> print repr([(t, t.post, t.topic) for t in post.topics.records.keys()]) </span><span class="lines">@@ -90,14 +88,14 @@ </span><span class="cx"> @access_control(action=actions.CreatePost()) </span><span class="cx"> def new_post(self, m, ARGS, blog_id): </span><span class="cx"> """provides a blank "submit a post" screen""" </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> self.template(m, '/blog/index.myt', loadcomponent='/blog/forms.myt:postform', form=form, blog=blog) </span><span class="cx"> </span><span class="cx"> @access_control(action=actions.EditPost()) </span><span class="cx"> def ajax_edit_post(self, m, ARGS, post_id): </span><span class="cx"> """produces an "edit post" screen, given the id of the post""" </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> self.reflect_from(form, post) </span><span class="cx"> m.comp('/blog/forms.myt:postform', form=form, blog=post.blog, post=post) </span><span class="lines">@@ -105,14 +103,14 @@ </span><span class="cx"> @access_control(action=actions.EditPost()) </span><span class="cx"> def ajax_delete_post(self, m, ARGS, post_id, confirm=False): </span><span class="cx"> """deletes a post, given its ID.""" </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> blog = post.blog </span><span class="cx"> if not confirm: </span><span class="cx"> m.comp('/blog/forms.myt:delete_confirm', post=post) </span><span class="cx"> return </span><span class="cx"> form = self.postform(m, ARGS) </span><del>- mapper.session().delete(post) - mapper.flush() </del><ins>+ self.sqlsess.delete(post) + self.sqlsess.flush() </ins><span class="cx"> form.append_success("Post deleted") </span><span class="cx"> m.comp('/blog/index.myt:postlist', blog=blog, form=form) </span><span class="cx"> </span><span class="lines">@@ -125,8 +123,8 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- #post = Post.mapper.options(nodefer('body')).get(post_id) - post = mapper.query(Post).get(post_id) </del><ins>+ #post = Post.self.sqlsess.options(nodefer('body')).get(post_id) + post = self.sqlsess.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerloginpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/login.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/login.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/login.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -1,5 +1,4 @@ </span><span class="cx"> import zblog.controller </span><del>-import zblog.database.mappers as mapper </del><span class="cx"> from zblog.domain.user import User </span><span class="cx"> import zblog.util.form as form </span><span class="cx"> import StringIO, os </span><span class="lines">@@ -24,7 +23,7 @@ </span><span class="cx"> f = self.form() </span><span class="cx"> f.set_request(ARGS) </span><span class="cx"> </span><del>- u = mapper.query(User).get_by(name=f['username'].display) </del><ins>+ u = self.sqlsess.query(User).get_by(name=f['username'].display) </ins><span class="cx"> if u is None or not u.checkpw(f['password'].display): </span><span class="cx"> u = None </span><span class="cx"> if u is not None: </span><span class="lines">@@ -62,7 +61,7 @@ </span><span class="cx"> form.append_error("Passwords do not match") </span><span class="cx"> form.isvalid=False </span><span class="cx"> </span><del>- existing = mapper.query(User).get_by(name=form['name'].value) </del><ins>+ existing = self.sqlsess.query(User).get_by(name=form['name'].value) </ins><span class="cx"> if existing is not None: </span><span class="cx"> form['name'].append_error("Username '%s' already exists" % form['name'].value) </span><span class="cx"> form.isvalid=False </span><span class="lines">@@ -71,12 +70,11 @@ </span><span class="cx"> self.template(m, '/register.myt', form=form) </span><span class="cx"> return </span><span class="cx"> </span><del>- sess = mapper.session() </del><span class="cx"> user = User() </span><span class="cx"> form.reflect_to(user) </span><span class="cx"> user.group=zblog.domain.user.user </span><del>- sess.save(user) - sess.flush() </del><ins>+ self.sqlsess.save(user) + self.sqlsess.flush() </ins><span class="cx"> form = self.form() </span><span class="cx"> form.append_success("Thanks for registering, %s!" % (user.name)) </span><span class="cx"> self.template(m, '/login.myt', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollermanageblogpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/manage/blog.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/manage/blog.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/manage/blog.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> import zblog.util.form as formutil </span><span class="cx"> from zblog.domain.user import User </span><span class="cx"> from zblog.domain.blog import Blog </span><del>-import zblog.database.mappers as mapper </del><span class="cx"> import zblog.domain.actions as actions </span><span class="cx"> from zblog.controller import access_control </span><span class="cx"> </span><span class="lines">@@ -12,7 +11,7 @@ </span><span class="cx"> if form is None: </span><span class="cx"> form = self.form(m) </span><span class="cx"> if blog_id: </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> form.reflect_from(blog) </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span><span class="cx"> </span><span class="lines">@@ -29,7 +28,7 @@ </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form, blog_id=blog_id) </span><span class="cx"> return </span><span class="cx"> </span><del>- owner = mapper.query(User).get_by(name=form['owner_name'].value) </del><ins>+ owner = self.sqlsess.query(User).get_by(name=form['owner_name'].value) </ins><span class="cx"> if owner is None: </span><span class="cx"> form.append_error("Could not locate user %s" % form['owner_name'].value) </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form, blog_id=blog_id) </span><span class="lines">@@ -37,15 +36,15 @@ </span><span class="cx"> </span><span class="cx"> if blog_id: </span><span class="cx"> created = False </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> else: </span><span class="cx"> created = True </span><span class="cx"> blog = Blog() </span><del>- mapper.session().save(blog) </del><ins>+ self.sqlsess.save(blog) </ins><span class="cx"> </span><span class="cx"> form.reflect_to(blog) </span><span class="cx"> blog.owner = owner </span><del>- mapper.flush() </del><ins>+ self.sqlsess.flush() </ins><span class="cx"> form.append_success("Blog '%s' %s" % (blog.name, created and 'created' or 'updated')) </span><span class="cx"> form.reflect_from(blog) </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span><span class="lines">@@ -53,7 +52,7 @@ </span><span class="cx"> @access_control(login=True, action=actions.EditBlog()) </span><span class="cx"> def delete_blog(self, m, ARGS, blog_id=None, confirm=False): </span><span class="cx"> form= self.form(m) </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = self.sqlsess.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> form.append_error("No blog found for id '%s'" % blog_id) </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form) </span><span class="lines">@@ -64,8 +63,8 @@ </span><span class="cx"> return </span><span class="cx"> </span><span class="cx"> name = blog.name </span><del>- mapper.delete(blog) - mapper.flush() </del><ins>+ self.sqlsess.delete(blog) + self.sqlsess.flush() </ins><span class="cx"> form.append_success("Blog '%s' deleted" % name) </span><span class="cx"> form.clear() </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollermanageuserpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/manage/user.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/manage/user.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/controller/manage/user.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -2,7 +2,6 @@ </span><span class="cx"> import zblog.util.form as formutil </span><span class="cx"> from zblog.domain.user import User </span><span class="cx"> from zblog.domain.blog import Blog </span><del>-import zblog.database.mappers as mapper </del><span class="cx"> import zblog.domain.actions as actions </span><span class="cx"> from zblog.controller import access_control </span><span class="cx"> </span><span class="lines">@@ -12,7 +11,7 @@ </span><span class="cx"> if form is None: </span><span class="cx"> form = self.form(m) </span><span class="cx"> if username is not None: </span><del>- user = mapper.query(User).get_by(name=username) </del><ins>+ user = self.sqlsess.query(User).get_by(name=username) </ins><span class="cx"> if user is not None: </span><span class="cx"> form.reflect_from(user) </span><span class="cx"> form['password_set'].required = False </span><span class="lines">@@ -35,7 +34,7 @@ </span><span class="cx"> form.append_error("Passwords do not match") </span><span class="cx"> </span><span class="cx"> if not user_id: </span><del>- existing = mapper.query(User).get_by(name=form['name'].value) </del><ins>+ existing = self.sqlsess.query(User).get_by(name=form['name'].value) </ins><span class="cx"> if existing is not None: </span><span class="cx"> form['name'].append_error("Username '%s' already exists" % form['name'].value) </span><span class="cx"> </span><span class="lines">@@ -45,13 +44,13 @@ </span><span class="cx"> </span><span class="cx"> if user_id: </span><span class="cx"> created = False </span><del>- user = mapper.query(User).get(user_id) </del><ins>+ user = self.sqlsess.query(User).get(user_id) </ins><span class="cx"> else: </span><span class="cx"> created = True </span><span class="cx"> user = User() </span><del>- mapper.session().save(user) </del><ins>+ self.sqlsess.save(user) </ins><span class="cx"> form.reflect_to(user) </span><del>- mapper.flush() </del><ins>+ self.sqlsess.flush() </ins><span class="cx"> form.append_success("User '%s' %s" % (user.name, created and 'created' or 'updated')) </span><span class="cx"> form.reflect_from(user) </span><span class="cx"> m.comp('/admin/user.myt:userform', form=form) </span><span class="lines">@@ -59,7 +58,7 @@ </span><span class="cx"> @access_control(login=True, action=actions.AdminUsers()) </span><span class="cx"> def delete_user(self, m, ARGS, user_id, confirm=False): </span><span class="cx"> form = self.form(m) </span><del>- user = mapper.query(User).get(user_id) </del><ins>+ user = self.sqlsess.query(User).get(user_id) </ins><span class="cx"> if user is None: </span><span class="cx"> form.append_error("Userid %d not found" % user_id) </span><span class="cx"> self.ajax_edituser(m, ARGS, form=form) </span><span class="lines">@@ -69,8 +68,8 @@ </span><span class="cx"> m.comp('/admin/user.myt:delete_confirm', user=user) </span><span class="cx"> return </span><span class="cx"> name = user.name </span><del>- mapper.session().delete(user) - mapper.flush() </del><ins>+ self.sqlsess.delete(user) + self.sqlsess.flush() </ins><span class="cx"> form.append_success("User '%s' deleted" % name) </span><span class="cx"> form.clear() </span><span class="cx"> m.comp('/admin/user.myt:userform', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogdatabasemapperspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/database/mappers.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/database/mappers.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/database/mappers.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -70,7 +70,7 @@ </span><span class="cx"> 'body':deferred(tables.posts.c.body), </span><span class="cx"> 'user':relation(user.User, lazy=True, backref='posts'), </span><span class="cx"> 'blog':relation(Blog, lazy=True, backref='posts'), </span><del>- 'topics':relation(TopicAssociation, lazy=False, private=True, association=Topic) </del><ins>+ 'topics':relation(TopicAssociation, lazy=False, private=True, association=Topic, backref='post') </ins><span class="cx"> }, is_primary=True, order_by=[desc(posts_with_ccount.c.datetime)]) </span><span class="cx"> </span><span class="cx"> # override 'posts' property on Blog to be private, so that posts get deleted when the blog does. </span><span class="lines">@@ -103,7 +103,7 @@ </span><span class="cx"> uses a mapper that does not lazy load replies or parents, and instead </span><span class="cx"> organizes comments into a hierarchical tree when the result is produced. </span><span class="cx"> """ </span><del>- q = query(Comment).options(noload('replies'), noload('parent')) </del><ins>+ q = session().query(Comment).options(noload('replies'), noload('parent')) </ins><span class="cx"> comments = q.select_by(post_id=post.id) </span><span class="cx"> result = [] </span><span class="cx"> d = {} </span><span class="lines">@@ -129,9 +129,3 @@ </span><span class="cx"> def session(): </span><span class="cx"> return trans.session </span><span class="cx"> </span><del>-def query(class_): - return trans.session.query(class_) - -def flush(): - trans.session.flush() - </del></span></pre></div> <a id="zblogtrunklibzblogdomainactionspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/domain/actions.py (1338 => 1339)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/domain/actions.py 2006-04-26 00:05:30 UTC (rev 1338) +++ zblog/trunk/lib/zblog/domain/actions.py 2006-04-26 00:06:04 UTC (rev 1339) </span><span class="lines">@@ -56,7 +56,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if blog_id and not user.is_administrator(): </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = mapper.session().query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> return False </span><span class="cx"> return user.id==blog.owner.id </span><span class="lines">@@ -68,7 +68,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if blog is None: </span><del>- blog = mapper.query(Blog).get(blog_id) </del><ins>+ blog = mapper.session().query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> return False </span><span class="cx"> return blog.owner.id==user.id or user.is_administrator() </span><span class="lines">@@ -78,7 +78,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if post is None: </span><del>- post = mapper.query(Post).get(post_id) </del><ins>+ post = mapper.session().query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> return False </span><span class="cx"> return post.user.id==user.id or user.is_administrator() or user.id==post.blog.owner.id </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-26 00:05:43
|
<!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>[1338] sqlalchemy/branches/schema/lib/sqlalchemy/orm: select_by was busted</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1338</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-25 19:05:30 -0500 (Tue, 25 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>select_by was busted</pre> <h3>Modified Paths</h3> <ul> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormmapperpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormpropertiespy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormquerypy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py</a></li> <li><a href="#sqlalchemybranchesschemalibsqlalchemyormsessionpy">sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="sqlalchemybranchesschemalibsqlalchemyormmapperpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py (1337 => 1338)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-25 23:48:01 UTC (rev 1337) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/mapper.py 2006-04-26 00:05:30 UTC (rev 1338) </span><span class="lines">@@ -803,7 +803,7 @@ </span><span class="cx"> return [] </span><span class="cx"> def copy(self): </span><span class="cx"> raise NotImplementedError() </span><del>- def get_criterion(self, key, value): </del><ins>+ def get_criterion(self, query, key, value): </ins><span class="cx"> """Returns a WHERE clause suitable for this MapperProperty corresponding to the </span><span class="cx"> given key/value pair, where the key is a column or object property name, and value </span><span class="cx"> is a value to be matched. This is only picked up by PropertyLoaders. </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormpropertiespy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py (1337 => 1338)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-25 23:48:01 UTC (rev 1337) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/properties.py 2006-04-26 00:05:30 UTC (rev 1338) </span><span class="lines">@@ -302,7 +302,7 @@ </span><span class="cx"> self.foreigntable = dependent[0] </span><span class="cx"> </span><span class="cx"> </span><del>- def get_criterion(self, key, value): </del><ins>+ def get_criterion(self, query, key, value): </ins><span class="cx"> """given a key/value pair, determines if this PropertyLoader's mapper contains a key of the </span><span class="cx"> given name in its property list, or if this PropertyLoader's association mapper, if any, </span><span class="cx"> contains a key of the given name in its property list, and returns a WHERE clause against </span><span class="lines">@@ -326,7 +326,7 @@ </span><span class="cx"> c = (self.mapper.table.c[key].columns[0]==value) & self.primaryjoin </span><span class="cx"> return c.copy_container() </span><span class="cx"> elif self.association is not None: </span><del>- c = self.mapper._get_criterion(key, value) & self.primaryjoin </del><ins>+ c = query._get_criterion(self.mapper, key, value) & self.primaryjoin </ins><span class="cx"> return c.copy_container() </span><span class="cx"> return None </span><span class="cx"> </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormquerypy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py (1337 => 1338)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-25 23:48:01 UTC (rev 1337) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/query.py 2006-04-26 00:05:30 UTC (rev 1338) </span><span class="lines">@@ -187,7 +187,7 @@ </span><span class="cx"> for key, value in params.iteritems(): </span><span class="cx"> if value is False: </span><span class="cx"> continue </span><del>- c = self._get_criterion(key, value) </del><ins>+ c = self._get_criterion(self.mapper, key, value) </ins><span class="cx"> if c is None: </span><span class="cx"> raise InvalidRequestError("Cant find criterion for property '"+ key + "'") </span><span class="cx"> if clause is None: </span><span class="lines">@@ -268,17 +268,17 @@ </span><span class="cx"> value.setup(key, statement, **kwargs) </span><span class="cx"> return statement </span><span class="cx"> </span><del>- def _get_criterion(self, key, value): </del><ins>+ def _get_criterion(self, mapper, key, value): </ins><span class="cx"> """used by select_by to match a key/value pair against </span><span class="cx"> local properties, column names, or a matching property in this mapper's </span><span class="cx"> list of relations.""" </span><del>- if self.props.has_key(key): - return self.props[key].columns[0] == value - elif self.table.c.has_key(key): - return self.table.c[key] == value </del><ins>+ if mapper.props.has_key(key): + return mapper.props[key].columns[0] == value + elif mapper.table.c.has_key(key): + return mapper.table.c[key] == value </ins><span class="cx"> else: </span><del>- for prop in self.props.values(): - c = prop.get_criterion(key, value) </del><ins>+ for prop in mapper.props.values(): + c = prop.get_criterion(self, key, value) </ins><span class="cx"> if c is not None: </span><span class="cx"> return c </span><span class="cx"> else: </span></span></pre></div> <a id="sqlalchemybranchesschemalibsqlalchemyormsessionpy"></a> <div class="modfile"><h4>Modified: sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py (1337 => 1338)</h4> <pre class="diff"><span> <span class="info">--- sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-25 23:48:01 UTC (rev 1337) +++ sqlalchemy/branches/schema/lib/sqlalchemy/orm/session.py 2006-04-26 00:05:30 UTC (rev 1338) </span><span class="lines">@@ -153,10 +153,10 @@ </span><span class="cx"> return self.bind_to </span><span class="cx"> else: </span><span class="cx"> return mapper.table.engine </span><del>- def query(self, mapper_or_class): </del><ins>+ def query(self, mapper_or_class, entity_name=None): </ins><span class="cx"> """given a mapper or Class, returns a new Query object corresponding to this Session and the mapper, or the classes' primary mapper.""" </span><span class="cx"> if isinstance(mapper_or_class, type): </span><del>- return query.Query(class_mapper(mapper_or_class), self) </del><ins>+ return query.Query(class_mapper(mapper_or_class, entity_name=entity_name), self) </ins><span class="cx"> else: </span><span class="cx"> return query.Query(mapper_or_class, self) </span><span class="cx"> def _sql(self): </span><span class="lines">@@ -212,13 +212,15 @@ </span><span class="cx"> is a list or tuple of objects specifically to be flushed.""" </span><span class="cx"> self.uow.flush(self, objects) </span><span class="cx"> </span><del>- def get(self, class_, *ident): </del><ins>+ def get(self, class_, *ident, **kwargs): </ins><span class="cx"> """given a class and a primary key identifier, loads the corresponding object.""" </span><del>- return self.query(class_).get(*ident) </del><ins>+ entity_name = kwargs.get('entity_name', None) + return self.query(class_, entity_name=entity_name).get(*ident) </ins><span class="cx"> </span><del>- def load(self, class_, *ident): </del><ins>+ def load(self, class_, *ident, **kwargs): </ins><span class="cx"> """given a class and a primary key identifier, loads the corresponding object.""" </span><del>- return self.query(class_).get(*ident) </del><ins>+ entity_name = kwargs.get('entity_name', None) + return self.query(class_, entity_name=entity_name).get(*ident) </ins><span class="cx"> </span><span class="cx"> def refresh(self, object): </span><span class="cx"> """reloads the attributes for the given object from the database, clears </span><span class="lines">@@ -286,7 +288,7 @@ </span><span class="cx"> # TODO: copy the state of the given object into this one. tricky ! </span><span class="cx"> inst = u.identity_map[key] </span><span class="cx"> else: </span><del>- inst = self.get(*key[1]) </del><ins>+ inst = self.get(object.__class__, *key[1]) </ins><span class="cx"> if obj is object: </span><span class="cx"> instance = inst </span><span class="cx"> </span></span></pre> </div> </div> </body> </html> |
From: <co...@sq...> - 2006-04-25 23:48:22
|
<!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>[1337] zblog/trunk/components: did a basic 0.2 conversion, using no threadlocals</title> </head> <body> <div id="msg"> <dl> <dt>Revision</dt> <dd>1337</dd> <dt>Author</dt> <dd>zzzeek</dd> <dt>Date</dt> <dd>2006-04-25 18:48:01 -0500 (Tue, 25 Apr 2006)</dd> </dl> <h3>Log Message</h3> <pre>did a basic 0.2 conversion, using no threadlocals</pre> <h3>Modified Paths</h3> <ul> <li><a href="#zblogtrunkcomponentsdatamyc">zblog/trunk/components/data.myc</a></li> <li><a href="#zblogtrunklibzblogcontroller__init__py">zblog/trunk/lib/zblog/controller/__init__.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerblogcommentspy">zblog/trunk/lib/zblog/controller/blog/comments.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerblogindexpy">zblog/trunk/lib/zblog/controller/blog/index.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerbootstrappy">zblog/trunk/lib/zblog/controller/bootstrap.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerfrontpy">zblog/trunk/lib/zblog/controller/front.py</a></li> <li><a href="#zblogtrunklibzblogcontrollerloginpy">zblog/trunk/lib/zblog/controller/login.py</a></li> <li><a href="#zblogtrunklibzblogcontrollermanageblogpy">zblog/trunk/lib/zblog/controller/manage/blog.py</a></li> <li><a href="#zblogtrunklibzblogcontrollermanageuserpy">zblog/trunk/lib/zblog/controller/manage/user.py</a></li> <li><a href="#zblogtrunklibzblogdatabase__init__py">zblog/trunk/lib/zblog/database/__init__.py</a></li> <li><a href="#zblogtrunklibzblogdatabasemapperspy">zblog/trunk/lib/zblog/database/mappers.py</a></li> <li><a href="#zblogtrunklibzblogdatabasetablespy">zblog/trunk/lib/zblog/database/tables.py</a></li> <li><a href="#zblogtrunklibzblogdomainactionspy">zblog/trunk/lib/zblog/domain/actions.py</a></li> </ul> </div> <div id="patch"> <h3>Diff</h3> <a id="zblogtrunkcomponentsdatamyc"></a> <div class="modfile"><h4>Modified: zblog/trunk/components/data.myc (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/components/data.myc 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/components/data.myc 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -5,6 +5,7 @@ </span><span class="cx"> </span><span class="cx"> <%global> </span><span class="cx"> from zblog.domain.blog import * </span><ins>+ from zblog.database.mappers import query </ins><span class="cx"> </%global> </span><span class="cx"> </span><span class="cx"> <%method bloglist> </span><span class="lines">@@ -14,9 +15,9 @@ </span><span class="cx"> </%args> </span><span class="cx"> <%init> </span><span class="cx"> if user is not None: </span><del>- blogs = Blog.mapper.select_by(owner_id=user.id) </del><ins>+ blogs = query(Blog).select_by(owner_id=user.id) </ins><span class="cx"> else: </span><del>- blogs = Blog.mapper.select() </del><ins>+ blogs = query(Blog).select() </ins><span class="cx"> if not m.has_content(): </span><span class="cx"> return blogs </span><span class="cx"> </%init> </span><span class="lines">@@ -43,7 +44,7 @@ </span><span class="cx"> keyword=False </span><span class="cx"> </%args> </span><span class="cx"> <%init> </span><del>- posts = Post.mapper.select_by(blog_id=blog.id, keyword=keyword) </del><ins>+ posts = query(Post).select_by(blog_id=blog.id, keyword=keyword) </ins><span class="cx"> if not m.has_content(): </span><span class="cx"> return posts </span><span class="cx"> </%init> </span></span></pre></div> <a id="zblogtrunklibzblogcontroller__init__py"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/__init__.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/__init__.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/__init__.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -2,7 +2,7 @@ </span><span class="cx"> </span><span class="cx"> __all__ = ['Controller', 'access_control'] </span><span class="cx"> </span><del>-from sqlalchemy import * </del><ins>+import zblog.database.mappers </ins><span class="cx"> </span><span class="cx"> class Controller(object): </span><span class="cx"> def template(self, m, template, **kwargs): </span><span class="lines">@@ -10,9 +10,10 @@ </span><span class="cx"> def get_user(self, m): </span><span class="cx"> s = m.get_session() </span><span class="cx"> u = s.get('user', None) </span><del>- # import_instance assures that the user deserialized from the session - # is properly present in the current thread's unit of work context. - return objectstore.import_instance(u) </del><ins>+ if u is not None: + return zblog.database.mappers.session().merge(u) + else: + return None </ins><span class="cx"> </span><span class="cx"> </span><span class="cx"> </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerblogcommentspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/blog/comments.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/blog/comments.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/blog/comments.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -15,7 +15,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -31,7 +31,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- comment = Comment.mapper.get(comment_id) </del><ins>+ comment = mapper.query(Comment).get(comment_id) </ins><span class="cx"> if comment is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -41,12 +41,12 @@ </span><span class="cx"> @access_control(action=actions.CreateComment()) </span><span class="cx"> def post(self, m, ARGS, post_id, parent_comment_id, confirm=False, preview=False): </span><span class="cx"> """posts a comment, or provides a preview display.""" </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="cx"> if parent_comment_id: </span><del>- parentcomment = Comment.mapper.get(parent_comment_id) </del><ins>+ parentcomment = mapper.query(Comment).get(parent_comment_id) </ins><span class="cx"> else: </span><span class="cx"> parentcomment = None </span><span class="cx"> form = self.commentform(m, ARGS, post, comment=parentcomment) </span><span class="lines">@@ -58,9 +58,9 @@ </span><span class="cx"> comment = self.createcomment(m, post, form, parentcomment) </span><span class="cx"> self.template(m, '/blog/postcomment.myt', post=post, form=form, comment=parentcomment, preview=comment) </span><span class="cx"> return </span><del>- mapper.begin() </del><span class="cx"> comment = self.createcomment(m, post, form, parentcomment) </span><del>- mapper.commit() </del><ins>+ mapper.session().save(comment) + mapper.flush() </ins><span class="cx"> form = self.commentform(m, ARGS, post, comment) </span><span class="cx"> form.append_success("Comment posted!") </span><span class="cx"> self.template(m, '/blog/postcomment.myt', post=post, comment=comment, form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerblogindexpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/blog/index.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/blog/index.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/blog/index.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -20,7 +20,7 @@ </span><span class="cx"> else: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="lines">@@ -29,12 +29,12 @@ </span><span class="cx"> @access_control(action=actions.CreatePost()) </span><span class="cx"> def post(self, m, ARGS, blog_id, post_id=None, preview=False): </span><span class="cx"> """submits a post, or previews it.""" </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> form.set_request(ARGS, validate=True) </span><span class="cx"> </span><span class="cx"> if post_id: </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> form.append_error("no post found for id '%s'" % post_id) </span><span class="cx"> self.template(m, '/blog/index.myt', blog=blog, loadcomponent='/blog/forms.myt:postform', form=form) </span><span class="lines">@@ -52,11 +52,12 @@ </span><span class="cx"> self.reflect_to(m, form, preview, blog) </span><span class="cx"> self.template(m, '/blog/index.myt', blog=blog, loadcomponent='/blog/forms.myt:postform', form=form, preview=preview, post=post) </span><span class="cx"> else: </span><del>- mapper.begin() </del><ins>+ sess = mapper.session() </ins><span class="cx"> if post is None: </span><span class="cx"> post = Post() </span><ins>+ sess.save(post) </ins><span class="cx"> self.reflect_to(m, form, post, blog) </span><del>- mapper.commit() </del><ins>+ mapper.flush() </ins><span class="cx"> if not post_id: </span><span class="cx"> form.append_success("Post added") </span><span class="cx"> else: </span><span class="lines">@@ -71,9 +72,10 @@ </span><span class="cx"> for keyword in form['topic_keywords'].value.split(' '): </span><span class="cx"> if not keyword: </span><span class="cx"> continue </span><del>- topic = Topic.mapper.get_by(keyword=keyword) </del><ins>+ topic = mapper.query(Topic).get_by(keyword=keyword) </ins><span class="cx"> if topic is None: </span><span class="cx"> topic = Topic(keyword=keyword, description=keyword) </span><ins>+ mapper.session().save(topic) </ins><span class="cx"> post.topics.append(TopicAssociation(post=post, topic=topic, is_primary=False)) </span><span class="cx"> </span><span class="cx"> print repr([(t, t.post, t.topic) for t in post.topics.records.keys()]) </span><span class="lines">@@ -88,14 +90,14 @@ </span><span class="cx"> @access_control(action=actions.CreatePost()) </span><span class="cx"> def new_post(self, m, ARGS, blog_id): </span><span class="cx"> """provides a blank "submit a post" screen""" </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> self.template(m, '/blog/index.myt', loadcomponent='/blog/forms.myt:postform', form=form, blog=blog) </span><span class="cx"> </span><span class="cx"> @access_control(action=actions.EditPost()) </span><span class="cx"> def ajax_edit_post(self, m, ARGS, post_id): </span><span class="cx"> """produces an "edit post" screen, given the id of the post""" </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> form = self.postform(m, ARGS) </span><span class="cx"> self.reflect_from(form, post) </span><span class="cx"> m.comp('/blog/forms.myt:postform', form=form, blog=post.blog, post=post) </span><span class="lines">@@ -103,15 +105,14 @@ </span><span class="cx"> @access_control(action=actions.EditPost()) </span><span class="cx"> def ajax_delete_post(self, m, ARGS, post_id, confirm=False): </span><span class="cx"> """deletes a post, given its ID.""" </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> blog = post.blog </span><span class="cx"> if not confirm: </span><span class="cx"> m.comp('/blog/forms.myt:delete_confirm', post=post) </span><span class="cx"> return </span><span class="cx"> form = self.postform(m, ARGS) </span><del>- mapper.begin() - mapper.delete(post) - mapper.commit() </del><ins>+ mapper.session().delete(post) + mapper.flush() </ins><span class="cx"> form.append_success("Post deleted") </span><span class="cx"> m.comp('/blog/index.myt:postlist', blog=blog, form=form) </span><span class="cx"> </span><span class="lines">@@ -125,7 +126,7 @@ </span><span class="cx"> m.abort(404) </span><span class="cx"> </span><span class="cx"> #post = Post.mapper.options(nodefer('body')).get(post_id) </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> m.abort(404) </span><span class="cx"> </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerbootstrappy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/bootstrap.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/bootstrap.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/bootstrap.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -38,6 +38,7 @@ </span><span class="cx"> connect = zblog.database.test_connection(dbtype, kwargs) </span><span class="cx"> error = None </span><span class="cx"> except Exception, e: </span><ins>+ raise </ins><span class="cx"> error = e </span><span class="cx"> m.comp('/bootstrap/index.myt:dboptions', dbtype=dbtype, form=self.form(ARGS), connected=(error is None), error=error) </span><span class="cx"> </span><span class="lines">@@ -59,7 +60,7 @@ </span><span class="cx"> dbform.description = desc['description'] </span><span class="cx"> f['dbtype'].value=dbtype </span><span class="cx"> for field in desc['arguments']: </span><del>- if dbtype == 'sqlite' and field[0] == 'filename': </del><ins>+ if dbtype == 'sqlite' and field[0] == 'host': </ins><span class="cx"> default = './data/zblog.db' </span><span class="cx"> else: </span><span class="cx"> default = field[2] </span><span class="lines">@@ -107,6 +108,7 @@ </span><span class="cx"> zblog.reset_config() </span><span class="cx"> os.remove(m.interpreter.attributes['config_file']) </span><span class="cx"> error = True </span><ins>+ raise </ins><span class="cx"> </span><span class="cx"> return (logger.getvalue(), error) </span><span class="cx"> </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerfrontpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/front.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/front.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/front.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -41,12 +41,15 @@ </span><span class="cx"> m.abort(404) </span><span class="cx"> return </span><span class="cx"> </span><del>- user = self.get_user(m) - login = getattr(controller.component_source.callable_, 'login', False) - if login and user is None: - login = m.fetch_component('/login/', resolver_context="frontcontroller", enable_dhandler=True) - m.subexec(login) - return </del><ins>+ if not zblog.need_config: + user = self.get_user(m) + login = getattr(controller.component_source.callable_, 'login', False) + if login and user is None: + login = m.fetch_component('/login/', resolver_context="frontcontroller", enable_dhandler=True) + m.subexec(login) + return + else: + user = None </ins><span class="cx"> </span><span class="cx"> action = getattr(controller.component_source.callable_, 'action', None) </span><span class="cx"> if action is not None: </span></span></pre></div> <a id="zblogtrunklibzblogcontrollerloginpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/login.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/login.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/login.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -24,7 +24,7 @@ </span><span class="cx"> f = self.form() </span><span class="cx"> f.set_request(ARGS) </span><span class="cx"> </span><del>- u = User.mapper.get_by(name=f['username'].display) </del><ins>+ u = mapper.query(User).get_by(name=f['username'].display) </ins><span class="cx"> if u is None or not u.checkpw(f['password'].display): </span><span class="cx"> u = None </span><span class="cx"> if u is not None: </span><span class="lines">@@ -62,7 +62,7 @@ </span><span class="cx"> form.append_error("Passwords do not match") </span><span class="cx"> form.isvalid=False </span><span class="cx"> </span><del>- existing = User.mapper.get_by(name=form['name'].value) </del><ins>+ existing = mapper.query(User).get_by(name=form['name'].value) </ins><span class="cx"> if existing is not None: </span><span class="cx"> form['name'].append_error("Username '%s' already exists" % form['name'].value) </span><span class="cx"> form.isvalid=False </span><span class="lines">@@ -71,11 +71,12 @@ </span><span class="cx"> self.template(m, '/register.myt', form=form) </span><span class="cx"> return </span><span class="cx"> </span><del>- mapper.begin() </del><ins>+ sess = mapper.session() </ins><span class="cx"> user = User() </span><span class="cx"> form.reflect_to(user) </span><span class="cx"> user.group=zblog.domain.user.user </span><del>- mapper.commit() </del><ins>+ sess.save(user) + sess.flush() </ins><span class="cx"> form = self.form() </span><span class="cx"> form.append_success("Thanks for registering, %s!" % (user.name)) </span><span class="cx"> self.template(m, '/login.myt', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollermanageblogpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/manage/blog.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/manage/blog.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/manage/blog.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -12,7 +12,7 @@ </span><span class="cx"> if form is None: </span><span class="cx"> form = self.form(m) </span><span class="cx"> if blog_id: </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> form.reflect_from(blog) </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span><span class="cx"> </span><span class="lines">@@ -29,24 +29,23 @@ </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form, blog_id=blog_id) </span><span class="cx"> return </span><span class="cx"> </span><del>- owner = User.mapper.get_by(name=form['owner_name'].value) </del><ins>+ owner = mapper.query(User).get_by(name=form['owner_name'].value) </ins><span class="cx"> if owner is None: </span><span class="cx"> form.append_error("Could not locate user %s" % form['owner_name'].value) </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form, blog_id=blog_id) </span><span class="cx"> return </span><span class="cx"> </span><del>- mapper.begin() - </del><span class="cx"> if blog_id: </span><span class="cx"> created = False </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> else: </span><span class="cx"> created = True </span><span class="cx"> blog = Blog() </span><ins>+ mapper.session().save(blog) </ins><span class="cx"> </span><span class="cx"> form.reflect_to(blog) </span><span class="cx"> blog.owner = owner </span><del>- mapper.commit() </del><ins>+ mapper.flush() </ins><span class="cx"> form.append_success("Blog '%s' %s" % (blog.name, created and 'created' or 'updated')) </span><span class="cx"> form.reflect_from(blog) </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span><span class="lines">@@ -54,7 +53,7 @@ </span><span class="cx"> @access_control(login=True, action=actions.EditBlog()) </span><span class="cx"> def delete_blog(self, m, ARGS, blog_id=None, confirm=False): </span><span class="cx"> form= self.form(m) </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> form.append_error("No blog found for id '%s'" % blog_id) </span><span class="cx"> self.ajax_editblog(m, ARGS, form=form) </span><span class="lines">@@ -65,9 +64,8 @@ </span><span class="cx"> return </span><span class="cx"> </span><span class="cx"> name = blog.name </span><del>- mapper.begin() </del><span class="cx"> mapper.delete(blog) </span><del>- mapper.commit() </del><ins>+ mapper.flush() </ins><span class="cx"> form.append_success("Blog '%s' deleted" % name) </span><span class="cx"> form.clear() </span><span class="cx"> m.comp('/admin/blog.myt:blogedit', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogcontrollermanageuserpy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/controller/manage/user.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/controller/manage/user.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/controller/manage/user.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -12,7 +12,7 @@ </span><span class="cx"> if form is None: </span><span class="cx"> form = self.form(m) </span><span class="cx"> if username is not None: </span><del>- user = User.mapper.get_by(name=username) </del><ins>+ user = mapper.query(User).get_by(name=username) </ins><span class="cx"> if user is not None: </span><span class="cx"> form.reflect_from(user) </span><span class="cx"> form['password_set'].required = False </span><span class="lines">@@ -35,7 +35,7 @@ </span><span class="cx"> form.append_error("Passwords do not match") </span><span class="cx"> </span><span class="cx"> if not user_id: </span><del>- existing = User.mapper.get_by(name=form['name'].value) </del><ins>+ existing = mapper.query(User).get_by(name=form['name'].value) </ins><span class="cx"> if existing is not None: </span><span class="cx"> form['name'].append_error("Username '%s' already exists" % form['name'].value) </span><span class="cx"> </span><span class="lines">@@ -43,16 +43,15 @@ </span><span class="cx"> self.ajax_edituser(m, ARGS, form=form) </span><span class="cx"> return </span><span class="cx"> </span><del>- mapper.begin() </del><span class="cx"> if user_id: </span><span class="cx"> created = False </span><del>- user = User.mapper.get(user_id) </del><ins>+ user = mapper.query(User).get(user_id) </ins><span class="cx"> else: </span><span class="cx"> created = True </span><span class="cx"> user = User() </span><del>- </del><ins>+ mapper.session().save(user) </ins><span class="cx"> form.reflect_to(user) </span><del>- mapper.commit() </del><ins>+ mapper.flush() </ins><span class="cx"> form.append_success("User '%s' %s" % (user.name, created and 'created' or 'updated')) </span><span class="cx"> form.reflect_from(user) </span><span class="cx"> m.comp('/admin/user.myt:userform', form=form) </span><span class="lines">@@ -60,7 +59,7 @@ </span><span class="cx"> @access_control(login=True, action=actions.AdminUsers()) </span><span class="cx"> def delete_user(self, m, ARGS, user_id, confirm=False): </span><span class="cx"> form = self.form(m) </span><del>- user = User.mapper.get(user_id) </del><ins>+ user = mapper.query(User).get(user_id) </ins><span class="cx"> if user is None: </span><span class="cx"> form.append_error("Userid %d not found" % user_id) </span><span class="cx"> self.ajax_edituser(m, ARGS, form=form) </span><span class="lines">@@ -70,9 +69,8 @@ </span><span class="cx"> m.comp('/admin/user.myt:delete_confirm', user=user) </span><span class="cx"> return </span><span class="cx"> name = user.name </span><del>- mapper.begin() - mapper.delete(user) - mapper.commit() </del><ins>+ mapper.session().delete(user) + mapper.flush() </ins><span class="cx"> form.append_success("User '%s' deleted" % name) </span><span class="cx"> form.clear() </span><span class="cx"> m.comp('/admin/user.myt:userform', form=form) </span></span></pre></div> <a id="zblogtrunklibzblogdatabase__init__py"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/database/__init__.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/database/__init__.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/database/__init__.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -1,6 +1,7 @@ </span><span class="cx"> """global database stuff. includes functions for finding out about database drivers, as well as the global SQLEngine used by the application.""" </span><span class="cx"> import zblog </span><span class="cx"> import sqlalchemy.engine </span><ins>+import sqlalchemy.engine.url as url </ins><span class="cx"> import sys </span><span class="cx"> </span><span class="cx"> def dbtypes(): </span><span class="lines">@@ -19,14 +20,17 @@ </span><span class="cx"> def test_connection(name, kwargs): </span><span class="cx"> """given a SQLEngine name and keyword arguments, creates a connection, or </span><span class="cx"> propigates whatever exceptions occur.""" </span><del>- e = sqlalchemy.engine.create_engine(name, kwargs) - e.connection() </del><ins>+ u = url.URL(name, **kwargs) + e = sqlalchemy.engine.create_engine(u) + e.connect() </ins><span class="cx"> </span><span class="cx"> def init_engine(): </span><span class="cx"> global engine </span><span class="cx"> conf = zblog.config['database'].copy() </span><span class="cx"> driver = conf.pop('driver') </span><del>- engine = sqlalchemy.engine.create_engine(driver, conf, echo=conf.pop('echo', False)) </del><ins>+ echo=conf.pop('echo', False) + u = url.URL(driver, **conf) + engine = sqlalchemy.engine.create_engine(u, echo=echo) </ins><span class="cx"> # load mapper module to intialize mapper attributes on domain classes </span><span class="cx"> __import__('zblog.database.mappers') </span><span class="cx"> </span><span class="lines">@@ -36,17 +40,17 @@ </span><span class="cx"> def init_database(admin_username, admin_password, logger): </span><span class="cx"> """creates database tables and inserts administrative user upon installation.""" </span><span class="cx"> import zblog.database.tables </span><del>- if zblog.database.tables.db != engine: - reload(zblog.database.tables) </del><span class="cx"> e = engine.echo </span><span class="cx"> engine.echo=True </span><span class="cx"> engine.logger=logger </span><span class="cx"> zblog.database.tables.create_tables() </span><span class="cx"> import zblog.domain.user as user </span><span class="cx"> import zblog.database.mappers as mapper </span><ins>+ mapper.start_session() </ins><span class="cx"> mapper.begin() </span><span class="cx"> try: </span><span class="cx"> u = user.User(admin_username, 'Administrator', admin_password, user.administrator) </span><ins>+ mapper.session().save(u) </ins><span class="cx"> mapper.commit() </span><span class="cx"> finally: </span><span class="cx"> engine.echo = e </span></span></pre></div> <a id="zblogtrunklibzblogdatabasemapperspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/database/mappers.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/database/mappers.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/database/mappers.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -1,5 +1,6 @@ </span><span class="cx"> """mapper.py - defines mappers for domain objects, mapping operations""" </span><span class="cx"> </span><ins>+import zblog.database </ins><span class="cx"> import zblog.database.tables as tables </span><span class="cx"> import zblog.domain.user as user </span><span class="cx"> from zblog.domain.blog import * </span><span class="lines">@@ -102,8 +103,8 @@ </span><span class="cx"> uses a mapper that does not lazy load replies or parents, and instead </span><span class="cx"> organizes comments into a hierarchical tree when the result is produced. </span><span class="cx"> """ </span><del>- mapper = Comment.mapper.options(noload('replies'), noload('parent')) - comments = mapper.select_by(post_id=post.id) </del><ins>+ q = query(Comment).options(noload('replies'), noload('parent')) + comments = q.select_by(post_id=post.id) </ins><span class="cx"> result = [] </span><span class="cx"> d = {} </span><span class="cx"> for c in comments: </span><span class="lines">@@ -119,31 +120,18 @@ </span><span class="cx"> </span><span class="cx"> Comment.find_by_post = staticmethod(find_by_post) </span><span class="cx"> </span><del>-# define a bunch of convenience methods on the objectstore. </del><ins>+trans = util.ThreadLocal() </ins><span class="cx"> </span><span class="cx"> def start_session(): </span><del>- """clears the objectstore, so that when a new user request is handled, all data will be - loaded from the database completely, and anything left over from the previous session - is removed. Clearing the objectstore is a thread-local operation.""" - objectstore.clear() - -# keep track of transaction token in a thread local. -# this is a compatibility hack since SQLAlchemy recently -# changed its begin/commit style to return this tranasctional token -# and the code is not keeping track of it, so we track it here -# within our own begin/commit -trans = util.ThreadLocal() </del><ins>+ """creates a new session for the start of a request.""" + trans.session = create_session(bind_to=zblog.database.engine) </ins><span class="cx"> </span><del>-def begin(): - """begins a transaction with the objectstore.""" - trans.t = objectstore.begin() </del><ins>+def session(): + return trans.session + +def query(class_): + return trans.session.query(class_) </ins><span class="cx"> </span><del>-def commit(): - """commits a transaction with the objectstore. everything modified since the last - begin() is updated in the database.""" - print "\n\n------------------------------\n\n" - trans.t.commit() </del><ins>+def flush(): + trans.session.flush() </ins><span class="cx"> </span><del>-def delete(*obj): - """marks an object (or objects) to be deleted upon the next commit().""" - objectstore.delete(*obj) </del></span></pre></div> <a id="zblogtrunklibzblogdatabasetablespy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/database/tables.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/database/tables.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/database/tables.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -1,10 +1,10 @@ </span><span class="cx"> from sqlalchemy import * </span><ins>+import zblog.database </ins><span class="cx"> </span><del>-from zblog.database import engine as db - </del><ins>+metadata = MetaData() </ins><span class="cx"> """application table metadata objects are described here.""" </span><span class="cx"> </span><del>-users = Table('users', db, </del><ins>+users = Table('users', metadata, </ins><span class="cx"> Column('user_id', Integer, primary_key=True), </span><span class="cx"> Column('user_name', String(30), nullable=False), </span><span class="cx"> Column('fullname', String(100), nullable=False), </span><span class="lines">@@ -12,14 +12,14 @@ </span><span class="cx"> Column('groupname', String(20), nullable=False), </span><span class="cx"> ) </span><span class="cx"> </span><del>-blogs = Table('blogs', db, </del><ins>+blogs = Table('blogs', metadata, </ins><span class="cx"> Column('blog_id', Integer, primary_key=True), </span><span class="cx"> Column('owner_id', Integer, ForeignKey('users.user_id'), nullable=False), </span><span class="cx"> Column('name', String(100), nullable=False), </span><span class="cx"> Column('description', String(500)) </span><span class="cx"> ) </span><span class="cx"> </span><del>-posts = Table('posts', db, </del><ins>+posts = Table('posts', metadata, </ins><span class="cx"> Column('post_id', Integer, primary_key=True), </span><span class="cx"> Column('blog_id', Integer, ForeignKey('blogs.blog_id'), nullable=False), </span><span class="cx"> Column('user_id', Integer, ForeignKey('users.user_id'), nullable=False), </span><span class="lines">@@ -29,19 +29,19 @@ </span><span class="cx"> Column('body', String), </span><span class="cx"> ) </span><span class="cx"> </span><del>-topics = Table('topics', db, </del><ins>+topics = Table('topics', metadata, </ins><span class="cx"> Column('topic_id', Integer, primary_key=True), </span><span class="cx"> Column('keyword', String(50), nullable=False), </span><span class="cx"> Column('description', String(500)) </span><span class="cx"> ) </span><span class="cx"> </span><del>-topic_xref = Table('topic_post_xref', db, </del><ins>+topic_xref = Table('topic_post_xref', metadata, </ins><span class="cx"> Column('topic_id', Integer, ForeignKey('topics.topic_id'), nullable=False), </span><span class="cx"> Column('is_primary', Boolean, nullable=False), </span><span class="cx"> Column('post_id', Integer, ForeignKey('posts.post_id'), nullable=False) </span><span class="cx"> ) </span><span class="cx"> </span><del>-comments = Table('comments', db, </del><ins>+comments = Table('comments', metadata, </ins><span class="cx"> Column('comment_id', Integer, primary_key=True), </span><span class="cx"> Column('user_id', Integer, ForeignKey('users.user_id'), nullable=False), </span><span class="cx"> Column('post_id', Integer, ForeignKey('posts.post_id'), nullable=False), </span><span class="lines">@@ -54,9 +54,5 @@ </span><span class="cx"> def create_tables(): </span><span class="cx"> """creates all application tables, used when the application is run for the </span><span class="cx"> first time.""" </span><del>- users.create() - blogs.create() - posts.create() - topics.create() - topic_xref.create() - comments.create() </del><span class="cx">\ No newline at end of file </span><ins>+ db = zblog.database.engine + metadata.create_all(engine=db) </ins></span></pre></div> <a id="zblogtrunklibzblogdomainactionspy"></a> <div class="modfile"><h4>Modified: zblog/trunk/lib/zblog/domain/actions.py (1336 => 1337)</h4> <pre class="diff"><span> <span class="info">--- zblog/trunk/lib/zblog/domain/actions.py 2006-04-25 05:44:11 UTC (rev 1336) +++ zblog/trunk/lib/zblog/domain/actions.py 2006-04-25 23:48:01 UTC (rev 1337) </span><span class="lines">@@ -6,8 +6,8 @@ </span><span class="cx"> import re, string </span><span class="cx"> import zblog </span><span class="cx"> from zblog.domain.blog import * </span><ins>+import zblog.database.mappers as mapper </ins><span class="cx"> </span><del>- </del><span class="cx"> actions = {} </span><span class="cx"> class ActionSingleton(type): </span><span class="cx"> def __call__(self): </span><span class="lines">@@ -56,7 +56,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if blog_id and not user.is_administrator(): </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> return False </span><span class="cx"> return user.id==blog.owner.id </span><span class="lines">@@ -68,7 +68,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if blog is None: </span><del>- blog = Blog.mapper.get(blog_id) </del><ins>+ blog = mapper.query(Blog).get(blog_id) </ins><span class="cx"> if blog is None: </span><span class="cx"> return False </span><span class="cx"> return blog.owner.id==user.id or user.is_administrator() </span><span class="lines">@@ -78,7 +78,7 @@ </span><span class="cx"> if user is None: </span><span class="cx"> return False </span><span class="cx"> if post is None: </span><del>- post = Post.mapper.get(post_id) </del><ins>+ post = mapper.query(Post).get(post_id) </ins><span class="cx"> if post is None: </span><span class="cx"> return False </span><span class="cx"> return post.user.id==user.id or user.is_administrator() or user.id==post.blog.owner.id </span></span></pre> </div> </div> </body> </html> |