Also, note that your solution will work specifically when using the 
generic.json view because that view does not require any of the 
response._vars values to be added to response._view_environment (because 
the view processes response._vars directly). But that solution will cause 
rendering of HTML views (and other views that rely on 
response._view_environment) to fail.

Anthony

On Sunday, December 2, 2012 8:35:57 AM UTC-5, Anthony wrote:
>
> response._view_environment has to contain all the web2py globals, 
> including the response object, so all of them will be available for use 
> when rendering the view. That means that when you return a dictionary to a 
> view, it cannot contain any top-level keys whose names clash with any of 
> the global objects, or they will be overwritten. This is generally not a 
> problem when rendering HTML because you're not rendering the keys in that 
> case (so the names don't really matter), but it can be an issue with JSON. 
> In this case, it's probably better to use the JSON service or generate the 
> JSON in the controller and return it directly rather than using the view to 
> generate it.
>
> Anthony
>
> On Sunday, December 2, 2012 1:10:13 AM UTC-5, Chris wrote:
>>
>> I've found a strange behavior in 1.99.7 (which is the same in 2.2.1 
>> except for a code cleanup issue).  This is either a bug or I'm confused 
>> (don't rule that out).  This is a long message -- I thought it was 
>> important to include a detailed demo of the phenomenon.
>>
>> The idea of generic views is wonderful -- a controller function can 
>> return a dict; and based on the extension used to request the page, data is 
>> returned using the formatting logic of the generic view of that type.  This 
>> works well and is demonstrated clearly in section 10.1.1 of the book.  A 
>> simple example:
>>
>>
>> In default.py ----------------
>>
>> def test():
>>     return dict(status='200 OK')
>>
>>
>> Then from a unix command line ----------------
>>
>> $ curl -L 'http://localhost:8000/default/test.load'
>> 200 OK
>>
>> $ curl -L 'http://localhost:8000/default/test.xml'
>> <?xml version="1.0" encoding="UTF-8"?><document><status>200 OK</status></
>> document>
>>
>> $ curl -L 'http://localhost:8000/default/test.json'
>> {
>>     "status": "200 OK"
>> }
>>
>>
>> ## note in JSON, I made a change in gluon / serializers.py to add indents
>>
>> So far so good.  But something bad happens when the dictionary is nested:
>>
>>
>> In updated default.py ----------------
>>
>> def test():
>>     return dict(response=dict(status='200 OK'))
>>
>>
>> requesting ...test.json creates an error file in my app/err folder 
>> ----------------
>>
>> Traceback (most recent call last):
>>   File "/Users/chris/dev/hsmaster/web2py_v1.99.7/gluon/main.py", line 508
>> , in wsgibase
>>     serve_controller(request, response, session)
>>   File "/Users/chris/dev/hsmaster/web2py_v1.99.7/gluon/main.py", line 207
>> , in serve_controller
>>     run_view_in(response._view_environment)
>>   File "/Users/chris/dev/hsmaster/web2py_v1.99.7/gluon/compileapp.py",line 
>> 596, in run_view_in
>>     badv = \'invalid view (%s)\' % response.view
>> AttributeError: \'dict\' object has no attribute \'view\'
>>
>>
>> Observations ----------------
>>
>> The book says "Any dictionary can be rendered in HTML, XML and JSON as 
>> long as it only contains python primitive types (int, float, string, list, 
>> tuple, dictionary)." so this seems in-bounds.  json.dumps (serializer 
>> users) has no problem with nested dicts.
>>
>> This may be a clue -- if we service-enable the same function and call 
>> differently ...
>>
>> @service.json
>> def test():
>>     return dict(response=dict(status='200 OK'))
>>
>>
>> ...  the result is fine ...
>>
>> $ curl -L 'http://localhost:8000/default/call/json/test'
>> {
>>     "response": {
>>         "status": "200 OK"
>>     }
>> }
>>
>>
>> or if we don't service-enable it, call like we did the first time, but 
>> change the name of the top-level key like this:
>>
>> def test():
>>     return dict(blahblah=dict(status='200 OK'))
>>
>>
>> ... the result is fine too ...
>>
>> $ curl -L 'http://localhost:8000/default/test.json'
>> {
>>     "blahblah": {
>>         "status": "200 OK"
>>     }
>> }
>>
>>
>> Conclusion ----------------
>>
>> After a long Wingare debugging session, I think this code is the 
>> proximate cause of the problem:
>>
>> in gluon / main.py / serve_controller():
>>
>> ...
>>     page = run_controller_in(request.controller, request.function,environment
>> )
>>     if isinstance(page, dict):
>>         response._vars = page
>>         for key in page:
>>             response._view_environment[key] = page[key]   ### AAA
>>         run_view_in(response._view_environment)
>>         page = response.body.getvalue()
>> ...
>>
>>
>> Basically it appears that the line marked AAA overwrites data in the 
>> response._view_environment structure with data from the dict the test() 
>> function returns.  The problem only happens when a key in the top level 
>> (not nested) of the dict matches an existing key in 
>> response._view_environment.  response._view_environment has 129 keys: A B 
>> BEAUTIFY ... auth cache crud ... response request service etc.) and when 
>> one of these is in common with the dict being rendered, the value of 
>> dict[key] overwrites it.
>>
>> The traceback above was from gluon / compileapp.py /  run_view_in() -- 
>> that relies on response._view_environment['response'] to have a key 'view', 
>> which is present before line AAA; but gone after 
>> -- response._view_environment['response'] has been clobbered.
>>
>>
>> Remediation ----------------
>>
>> In my debugging, I changed line AAA to be a pass statement and nothing 
>> bad happened.  I don't know if that is the right approach or not.  The same 
>> little block of code I showed above (from main.py) also occurs twice in 
>> compileapp.py.  I don't know enough to judge whether eliminating line AAA 
>> as I did is a good idea or not; or if it should be done in some or all of 
>> the three location.
>>
>>
>> Request ----------------
>>
>> Can someone say if my solution is on the right track; and why the dict is 
>> being merged with the response?  Maybe the right approach for a different 
>> payload -- but dicts can't avoid using these keys.  view, title, status, db 
>> -- these are pretty common keys.
>>
>>
>> Best regards and thanks --
>>
>

-- 



Reply via email to