Hi all,

Is there any practical reason that the type of the `environ` object must be 
exactly `dict`, as specified in PEP3333?  

I'm asking because it was recently pointed out that gevent's WSGI server can 
sometimes print `environ` (on certain error cases), but that can lead to 
sensitive information being kept in the server's logs (e.g., 
HTTP_AUTHORIZATION, HTTP_COOKIE, maybe other things). The simplest and most 
flexible way to prevent this from happening, not just inadvertently within 
gevent itself but also for client applications, I thought, was to have 
`environ` be a subclass of `dict` with a customized `__repr__` (much like WebOb 
does for MultiDict, and repoze.who does for Identity, both for similar reasons).

Unfortunately, when I implemented that in [0], I discovered that 
`wsgiref.validator` asserts that type(environ) is dict. I looked up the PEP, 
and sure enough, PEP 3333 states that environ "must be a builtin Python 
dictionary (not a subclass, UserDict or other dictionary emulation)." [1]


That seemed overly restrictive to me, so I tried to backtrack the history of 
that language in hopes of discovering the rationale. 

- It was present in the predecessor of PEP 3333, PEP 0333, in the first version 
committed to the repository in August 2004. [2] 
- Prior to that, it was in both drafts of what would become PEP 0333 posted to 
this mailing list, again from August 2004: [3], [4].
- The ancestor of those drafts, the "Python Web Container Interface v1.0" was 
posted in December of 2003 with somewhat less restrictive language: "the 
environ object *must* be a Python dictionary....The rationale for requiring a 
dictionary is to maximize portability
between containers" [5].

Now, the discussion on that earliest draft in [5] specifically brought up using 
other types that implement all the methods of a dictionary, like 
UserDict.DictMixin [6]. The last post on the subject in that thread seemed to 
be leaning towards accepting non-dict objects, at least if they were good 
enough [7].

By the time the draft became recognizable as the precursor to PEP 0333 in [3], 
the very strict language we have now was in place. That draft, however, 
specifically stated that it was intended to be compatible with Python 1.5.2. In 
Python 1.5.2, it wasn't possible to subclass the builtin dict, so imitations, 
like UserDict.DictMixin, were necessarily imprecise. This was later changed to 
the much-maligned Python 2.2.2 release [8]; Python 2.2 added the ability to 
subclass dict, but the language wasn't changed.


Given that today, we can subclass dict with full fidelity, is there still any 
practical reason not to be able to do so? I'm probably OK with gevent violating 
the letter of the spec in this regard, so long as there are no practical 
consequences. I was able to think of two possible objections, but both can be 

- Pickling the custom `environ` type and then loading it in another process 
might not work if the class is not available. I can imagine this coming up with 
Celery, for example. This is easily fixed by adding an appropriate 
`__reduce_ex__` implementation.

- Code somewhere relies on `if type(some_object) is dict:` (where `environ` 
became `some_object`, presumably through several levels of calls), instead of 
`isinstance(some_object, dict)` or `isinstance(some_object, 
collections.MutableMapping)`. The solution here is simply to not do that :) 
Pylint, among other linters, produces warnings if you do.

Can anyone think of any other practical reasons I've overlooked? Is this just a 
horrible idea for other reasons?

I appreciate any discussion!


[0] https://github.com/gevent/gevent/compare/secure-environ
[1] https://www.python.org/dev/peps/pep-3333/#specification-details
[3] https://mail.python.org/pipermail/web-sig/2004-August/000518.html
[4] https://mail.python.org/pipermail/web-sig/2004-August/000562.html
[5] https://mail.python.org/pipermail/web-sig/2003-December/000394.html
[7] https://mail.python.org/pipermail/web-sig/2003-December/000401.html
[8] https://mail.python.org/pipermail/web-sig/2004-August/000565.html

Web-SIG mailing list
Web SIG: http://www.python.org/sigs/web-sig

Reply via email to