This is an interesting idea. Instead of bothering with the "compact" 
attribute, we could make it so any Row object automatically works like a 
"compact" Row whenever it includes only one top-level key. So, if you have:

<Row {'person': {'first_name': 'Bob', 'last_name': 'Smith'}}>

you could do either row.person.first_name or row.first_name, regardless of 
the value of the "compact" attribute. The problem, though, is what happens 
if there is a field name that is the same as the table name. In that case, 
we would have to make the default to return either the full sub-record 
associated with the table, or just the field within the table, but neither 
approach would be fully backward compatible.

I suppose we could keep using the "compact" attribute, and simply pass it 
to the Row object, so the Row object itself knows whether it is compact or 
not. This would also be necessary for the Row.as_dict and related methods 
to remain backward compatible. But then the Row object needs to be able to 
hold a private attribute (e.g., __compact).

Thoughts on this?

Anthony

On Wednesday, January 8, 2014 9:41:19 AM UTC-5, Anthony wrote:
>
> Let's discuss on the developers 
> list<https://groups.google.com/forum/?fromgroups=#!topic/web2py-developers/k2D6MVfBEYo>
> .
>
> On Tuesday, January 7, 2014 9:52:16 PM UTC-5, Joe Barnhart wrote:
>>
>> 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 web2py+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to