> On Jan 24, 2017, at 12:48 PM, Craig Rodrigues <rodr...@crodrigues.org> wrote: > > > > On Mon, Jan 23, 2017 at 5:10 PM, Jean-Paul Calderone > <exar...@twistedmatrix.com <mailto:exar...@twistedmatrix.com>> wrote: > On Mon, Jan 23, 2017 at 7:08 PM, Craig Rodrigues <rodr...@crodrigues.org > <mailto:rodr...@crodrigues.org>> wrote: > > > > I did some more debugging. The callstack is quite deep. :/ > I used this command to trigger the error: > > trial > buildbot.test.unit.test_process_buildrequestdistributor.TestMaybeStartBuilds.test_slow_db > > I found in this function in buildbot's BuildRequestsEndpoint.get() function ( > https://github.com/buildbot/buildbot/blob/master/master/buildbot/data/buildrequests.py#L146 > > <https://github.com/buildbot/buildbot/blob/master/master/buildbot/data/buildrequests.py#L146> > ) there is this line: > > defer.returnValue( > [(yield self.db2data(br)) for br in buildrequests]) > > On Python 2, this line returns: > an object list > each list entry is a dictionary of name/value pairs that looks like: > [{'buildrequestid': 10, 'complete': False, 'waited_for': False, 'claimed_at': > None, 'results': -1, 'claimed': False, 'buildsetid': 11, 'complete_at': None, > 'submitted_at': datetime.datetime(1970, 1, 2, 12, 6, 40, tzinfo=tzutc()), > 'builderid': 77, 'claimed_by_masterid': None, 'priority': 0}, > {'buildrequestid': 11, 'complete': False, 'waited_for': False, 'claimed_at': > None, 'results': -1, 'claimed': False, 'buildsetid': 11, 'complete_at': None, > 'submitted_at': datetime.datetime(1970, 1, 2, 13, 30, tzinfo=tzutc()), > 'builderid': 77, 'claimed_by_masterid': None, 'priority': 0}] > > > On Python 3, this returns: > an object <generator object BuildRequestsEndpoint.get.<locals>.<listcomp> > of type <class 'generator'> > > > Yep. > > On Python 2, [(yield self.db2data(br)) for br in buildrequests] is a list > comprehension. It will have len(buildrequests) elements and each will be the > value sent back in to the generator via the yield expression. > > On Python 3, the same expression is a list of one element which is a > generator expression. > > This form is much clearer, I think, and behaves as intended on both versions > of Python: > > results = [] > for br in buildrequests: > results.append((yield self.db2data(br))) > defer.returnValue(results) > > > > Wow, thanks! That fixed it. I submitted those fixes upstream to buildbot. > > I'm not so familiar with generator expressions and Deferred's so have been > playing > around with things to try to understand. > > I went back to the problem code, and changed: > > defer.returnValue( > [(yield self.db2data(br)) for br in buildrequests]) > > to: > > defer.returnValue( > list([(yield self.db2data(br)) for br in buildrequests]) > > and ran the code under Python 3 and got a return value of: > > [ Deferred ] > > instead of: > [ {......} ] > > where the Deferred.results value was the dictionary. > > How does Python 2 directly go to returning the dictionary out of the Deferred, > while Python 3 returns the Deferred inside the list? self.db2data() returns > a Deferred.
I've encountered this before and quickly worked around it, but I think this might actually be a bug in python 3, or at least its documentation. The language docs officially say that a "list display" (which is what I believe we're looking at here) "yields a new list object". But that is not what I see here: >>> [(yield 1) for x in range(10)] <generator object <listcomp> at 0x10cd210f8> That is a comprehension enclosed in square brackets, but I'm getting a generator object out rather than a list. Is there a PEP for this that just hasn't updated the language reference? -glyph
_______________________________________________ Twisted-Python mailing list Twisted-Python@twistedmatrix.com http://twistedmatrix.com/cgi-bin/mailman/listinfo/twisted-python