3
# Copyright 2007 Google Inc.
5
# Licensed under the Apache License, Version 2.0 (the "License");
6
# you may not use this file except in compliance with the License.
7
# You may obtain a copy of the License at
9
# http://www.apache.org/licenses/LICENSE-2.0
11
# Unless required by applicable law or agreed to in writing, software
12
# distributed under the License is distributed on an "AS IS" BASIS,
13
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
# See the License for the specific language governing permissions and
15
# limitations under the License.
21
"""A request-local environment and logging stream."""
34
_sys_stderr = sys.stderr
37
class RequestEnvironment(threading.local):
38
"""A thread local request environment.
40
A thread local request environment that provides an error stream errors and a
41
dict of the request environment environ as would be found in os.environ. A
42
single error stream is shared between threads of a single request, but each
43
thread accesses an independent copy of environ created when
44
CloneRequestEnvironment is called. A request environment of one thread can be
45
installed in another thread as follows:
46
1. Call CloneRequestEnvironment in the first thread.
47
2. Call the returned callable from the other thread.
51
super(RequestEnvironment, self).__init__()
55
"""Resets the error stream and environment for this request."""
56
self.errors = _sys_stderr
59
def Init(self, errors, environ):
61
self.environ = environ
63
def CloneRequestEnvironment(self):
64
"""Returns a callable that will install the environment in another thread.
67
A callable that will duplicate the request environment of this thread in
68
another thread that calls it.
71
environ = dict(self.environ)
72
return lambda: self.Init(errors, environ)
75
"""Clears the thread locals."""
80
class RequestLocalStream(object):
81
"""A stream that delegates to a RequestEnvironment stream."""
83
def __init__(self, request):
84
self._request = request
90
self._request.errors.flush()
92
def write(self, data):
93
self._request.errors.write(data)
95
def writelines(self, data):
96
self._request.errors.writelines(data)
99
class RequestLocalEnviron(collections.MutableMapping):
100
"""A MutableMapping that delegates to a RequestEnvironment environ."""
102
def __init__(self, request):
103
self._request = request
106
return len(self._request.environ)
109
return iter(self._request.environ)
111
def __getitem__(self, key):
112
return self._request.environ[key]
114
def __setitem__(self, key, value):
115
self._request.environ[key] = value
117
def __delitem__(self, key):
118
del self._request.environ[key]
121
return repr(self._request.environ)
123
def has_key(self, key):
124
return key in self._request.environ
127
return dict(self._request.environ)
132
return collections.ItemsView(self)
135
return collections.KeysView(self)
137
def viewvalues(self):
138
return collections.ValuesView(self)
141
current_request = RequestEnvironment()
146
def PatchOsEnviron():
147
"""Replace os.environ by a RequestLocalEnviron instance.
149
This is called from init.py when it modifies the execution
150
environment (in the wider sense of the word).
152
os.environ = RequestLocalEnviron(current_request)