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 -- >> > --

