Maybe the best answer is to change Row so that it always holds the full set
of keys (table:field) and change the __getitem__ method to look up the key
recursively if only one part is provided. Here is a sample method which
implements this strategy of testing keys for dicts within dicts. Our case
is a little simpler since we never "recurse" more than one level deep.
def _finditem(obj, key):
if key in obj: return obj[key]
for k, v in obj.items():
if isinstance(v,dict):
item = _finditem(v, key)
if item is not None:
return item
This has the advantage of working with existing code and preserving as much
information as possible in the Row object. I have a feeling this could
make the internals of web2py a good deal more consistent. Less testing for
special cases is always good!
-- Joe B.
On Tuesday, January 7, 2014 3:48:39 PM UTC-8, Anthony wrote:
>
> Note, same problem with .sort (it modifies the Row objects in
> self.records), so we should probably fix that as well (will be a bit more
> complicated).
>
> Anthony
>
> On Tuesday, January 7, 2014 11:03:56 AM UTC-5, 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 [email protected].
For more options, visit https://groups.google.com/groups/opt_out.