It's actually a little deeper problem. I see that Rows.sort() has the effect of stripping the table key from the resulting Row objects.
If I try the obvious fix, to use the built-in "sorted" on self.records instead of self, then the next problem surfaces -- the supplied sort key must include the table and the field key, and they must both be supplied to the sort. Which would break all manner of existing programs. I love the concept of "compact" vs non-compact, but the implementation of stripping the table keys from the Row objects has left quite a mess! -- Joe On Tuesday, January 7, 2014 8:03:56 AM UTC-8, Anthony wrote: > > The Rows.find() method does the following: > > for row in self: > if f(row): > if a<=k: records.append(row) > k += 1 > if k==b: break > > In a Rows object, there is self.records, which is a list of Row objects. > Each Row object has at least one top-level key with the table name, and the > record is stored in the value associated with that key: > > <Row {'person': {'first_name': 'Bob', 'last_name': 'Smith'}}> > > When .find() is called on a Rows object with compact=True, the __iter__ > method (called by the "for row in self" loop) returns a transformed version > of each Row object, removing the top-level table key: > > <Row {'first_name': 'Bob', 'last_name': 'Smith'}> > > I believe this is an unnecessary transformation, and it is what is > subsequently causing the .render() method to fail (the .render() method > expects the top-level table key to be there, whether or not compact=True). > I propose the following change to .find(): > > for i, row in enumerate(self): > if f(row): > if a<=k: records.append(self.records[i]) > k += 1 > if k==b: break > > The above code appends self.records[i] instead of row, which preserves the > original Row objects instead of including transformed objects. Anyone see > any problems with that change? > > Also, is there any reason all of the Rows methods (i.e., find, exclude, > __and__, __or__) should not be preserving the "compact" attribute of the > original Rows object? Perhaps we should change them all to do so. (Note, > this is a separate issue unrelated to the above problem with .find() and > .render().) > > Anthony > > On Tuesday, January 7, 2014 10:47:28 AM UTC-5, Anthony wrote: >> >> .render() works fine on Rows objects with compact=True, and it also works >> fine on the results of .sort(), .exclude(), &, and | operations. The only >> problem is with the results of .find() operations when the original Rows >> object has compact=True. The problem is that the .find() method modifies >> the Row objects in self.records when compact=True, which it probably should >> not due. >> >> Aside from this issue, perhaps the various Rows methods should preserve >> the "compact" attribute -- not sure why they don't. >> >> Forwarding to the developers list for discussion. >> >> Anthony >> >> On Tuesday, January 7, 2014 3:10:00 AM UTC-5, Joe Barnhart wrote: >>> >>> I've been experimenting with the render method of the Rows class, and I >>> am very impressed. But one drawback I found is that the Rows object must >>> have its value set to "compact=False" to work properly with render(). It >>> isn't a problem if the Rows object is used directly without any operators, >>> but I discovered that many, if not most, Rows methods do not preserve the >>> "compact" setting. >>> >>> For example. if you "sort" the Rows, it leaves compact=True. Ditto, if >>> you use "extract" or "find" on the Rows object. The "&" and "|" operators >>> also set the compact variable to "True". The upshot is that you can't use >>> any of these operators on the Rows object and then use "render" on the >>> resulting object. >>> >>> It is a simple change to add the preservation of the "compact" flag >>> during any of these steps, but I'm unsure if this will break existing code. >>> Other than coming up with a completely parallel set of methods, which >>> leave compact set the way it came in, I can't think of another approach >>> will be provably backwards-compatible. >>> >>> Here is an example: >>> >>> >>> def __and__(self,other): >>> if self.colnames!=other.colnames: >>> raise Exception('Cannot & incompatible Rows objects') >>> records = self.records+other.records >>> return Rows(self.db,records,self.colnames) >>> >>> >>> Becomes: >>> >>> >>> def __and__(self,other): >>> if self.colnames!=other.colnames: >>> raise Exception('Cannot & incompatible Rows objects') >>> records = self.records+other.records >>> return Rows(self.db,records,self.colnames,compact=(self.compact >>> or other.compact)) >>> >>> >>> In the case above, the flag compact will be set True if either of the >>> participating Rows object is also "compact". My logic is, if you've lost >>> the "table" values on either Rows object, you may as well lose them on the >>> combined set. >>> >>> What do you think? >>> >>> -- Joe B. >>> >>> >>> -- Resources: - http://web2py.com - http://web2py.com/book (Documentation) - http://github.com/web2py/web2py (Source code) - https://code.google.com/p/web2py/issues/list (Report Issues) --- You received this message because you are subscribed to the Google Groups "web2py-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to web2py+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.