-
Notifications
You must be signed in to change notification settings - Fork 0
/
test_wsgi_lite.py
executable file
·164 lines (138 loc) · 5.34 KB
/
test_wsgi_lite.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
def piglatin(text):
"""Quick and dirty, regex-based pig latin converter"""
pl_re="""
(?ix) # Verbose processing, ignore case
(\W|^) # Start of word or string
(?! (?: the|\w{0,2})(?:\W|$)) # Don't match 'the' or two-letter words
(\w*?)([aeiouy]\w*)
(?= \W|$) # End of word or string
""".encode('ascii')
import re
def cvt(m):
pre, head, tail = m.groups()
return pre+tail+(head or 'w'.encode('ascii'))+'ay'.encode('ascii')
return re.sub(pl_re, cvt, text)
def latinator(app):
from wsgi_lite import lite, lighten
def middleware(environ):
status, headers, body = app(environ)
for name, value in headers:
if name.lower() == 'content-type' and value == 'text/plain':
break
else:
# Not text/plain, pass it through unchanged
return status, headers, body
# Strip content-length if present, else it'll be wrong
headers = [
(name, value) for name, value in headers
if name.lower() != 'content-length'
]
def pliter(body): # Python 2.3 doesn't do generator expressions
for data in body: yield piglatin(data)
return status, headers, pliter(body)
# Make sure that `app` can be invoked via the Lite protocol
app = lighten(app)
return lite(middleware)
def test(app, environ={}, form={}, _debug=True, **kw):
"""Print the output of a WSGI app
Runs `app` as a WSGI application and prints its output. If an untrapped
error occurs in `app`, it drops into the ``pdb`` debugger's post-mortem
debug shell (using ``sys.__stdout__`` if ``sys.stdout`` has been replaced).
Any keyword arguments are added to the environment used to run `app`. If
a keyword argument begins with ``wsgi_``, the ``_`` is replaced with a
``.``, so that you can set e.g. ``wsgi.multithread`` using a
``wsgi_multithread`` keyword argument.
If a non-empty `form` dictionary is provided, it is treated as a collection
of fields for a form ``POST``. The ``REQUEST_METHOD`` will default to
``POST``, and the default ``CONTENT_LENGTH``, ``CONTENT_TYPE``, and
``wsgi.input`` values will be appropriately set (but can still be
overridden by explicit keyword arguments or the `environ` argument).
Any `form` values that are not instances of ``basestring`` are assumed to
be *sequences* of values, and will result in multiple name/value pairs
being added to the encoded data sent to the application.
Any WSGI-required variables that are not specified by `environ`, `form`, or
keyword arguments, are initialized to default values using the
``wsgiref.util.setup_testing_defaults()`` function.
"""
import sys
from wsgiref.util import setup_testing_defaults
from wsgiref.handlers import BaseCGIHandler
try:
from StringIO import StringIO
except ImportError:
from io import BytesIO as StringIO
try:
from urllib import quote_plus
except ImportError:
from urllib.parse import quote_plus
environ = environ.copy()
for k, v in kw.items():
if k.startswith('wsgi_'):
environ[k.replace('_','.',1)] = v
else:
environ[k] = v
if form:
encoded = []
for k, v in form.items():
if isinstance(v,basestring):
v = [v]
for v in v:
encoded.append('%s=%s' % (quote_plus(k), quote_plus(v)))
encoded = '&'.join(encoded)
environ.setdefault('wsgi.input', StringIO(encoded))
environ.setdefault('CONTENT_LENGTH', str(len(encoded)))
environ.setdefault('CONTENT_TYPE', 'application/x-www-form-urlencoded')
environ.setdefault('REQUEST_METHOD', 'POST')
setup_testing_defaults(environ)
stdout = StringIO()
stderr = environ['wsgi.errors']
def wrapper(env, start):
try:
return app(env, start)
except:
if _debug:
stdout = sys.stdout
try:
if stdout is not sys.__stdout__:
sys.stdout = sys.__stdout__
#import pdb
#pdb.post_mortem(sys.exc_info()[2])
finally:
sys.stdout = stdout
raise
def print_output(io):
b = io.getvalue()
if type(b) is not str: b = b.decode('latin-1')
print (b.replace('\r\n', '\n'))
BaseCGIHandler(
environ['wsgi.input'], stdout, stderr, environ,
environ['wsgi.multithread'], environ['wsgi.multiprocess']
).run(wrapper)
print_output(stdout)
if stderr.getvalue():
print ("--- Log Output ---")
print_output(stderr)
def additional_tests():
import sys
tests = ['tests.txt']
if sys.version>='2.4':
tests.append('README.rst')
try:
from greenlet import greenlet
except ImportError:
pass
else:
tests.append('greenlet-tests.txt')
try:
from peak.util.proxies import AbstractWrapper
except ImportError:
pass
else:
tests.append('proxy-tests.txt')
import doctest
return doctest.DocFileSuite(
optionflags = doctest.ELLIPSIS
| doctest.NORMALIZE_WHITESPACE
, #| doctest.REPORT_ONLY_FIRST_FAILURE,
*tests
)