summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorianb <devnull@localhost>2005-05-17 03:06:22 +0000
committerianb <devnull@localhost>2005-05-17 03:06:22 +0000
commited51c888895583a856f40ce951c0c131a26f9ca3 (patch)
tree8f56068ec37a20406eab36c1f4a86ff233a5ddb8
parenta3ce49f606ece7bfc639a7d27fa6a4c50b0b8b37 (diff)
downloadpaste-ed51c888895583a856f40ce951c0c131a26f9ca3.tar.gz
A bunch of pylint-inspired changes; all minor code cleanup
-rw-r--r--paste/app_setup.py14
-rw-r--r--paste/cgitb_catcher.py11
-rw-r--r--paste/configmiddleware.py1
-rw-r--r--paste/errormiddleware.py23
-rw-r--r--paste/gzipper.py1
-rw-r--r--paste/httpexceptions.py2
-rw-r--r--paste/lint.py117
-rw-r--r--paste/pycgiwrapper.py9
-rw-r--r--paste/pyconfig.py14
-rw-r--r--paste/recursive.py10
-rw-r--r--paste/reloader.py21
-rwxr-xr-xpaste/server.py1
-rw-r--r--paste/tests/fixture.py21
-rw-r--r--paste/threaded.py436
-rw-r--r--paste/urlparser.py3
-rw-r--r--paste/util/threadedprint.py32
-rw-r--r--paste/wdg_validate.py32
-rw-r--r--paste/wsgilib.py10
18 files changed, 174 insertions, 584 deletions
diff --git a/paste/app_setup.py b/paste/app_setup.py
index 007b9d5..a0b6047 100644
--- a/paste/app_setup.py
+++ b/paste/app_setup.py
@@ -49,7 +49,8 @@ def find_template_info(args):
except ImportError, e:
raise InvalidCommand(
'No template exists by the name %r (%s)' % (template_name, e))
- return (server_conf_fn, template_name, os.path.dirname(template_mod.__file__), template_mod)
+ return (server_conf_fn, template_name,
+ os.path.dirname(template_mod.__file__), template_mod)
def find_template_option(args):
copy = args[:]
@@ -102,6 +103,7 @@ class CommandRunner(object):
self.commands = {}
self.command_aliases = {}
self.register_standard_commands()
+ self.server_conf_fn = None
def run(self, argv, template_name, template_dir, template_module,
server_conf_fn):
@@ -259,9 +261,11 @@ class CommandList(Command):
if self.args and not fnmatch.fnmatch(name, self.args[0]):
continue
if not self.options.verbose:
- print '%s: %s\n' % (name, self.template_description().splitlines()[0])
+ print '%s: %s\n' % (
+ name, self.template_description().splitlines()[0])
else:
- return '%s: %s\n' % (self.name, self.template_description())
+ return '%s: %s\n' % (
+ self.name, self.template_description())
# @@: for verbosity >= 2 we should give lots of metadata
any = True
if not any:
@@ -346,8 +350,8 @@ class CommandCreate(Command):
template_options['absolute_parent'] = os.path.dirname(
os.path.abspath(output_dir))
template_options['template_name'] = self.template_name
- self.copy_dir(file_dir, output_dir, template_options, self.options.verbose,
- self.options.simulate)
+ self.copy_dir(file_dir, output_dir, template_options,
+ self.options.verbose, self.options.simulate)
def copy_dir(self, *args, **kw):
copy_dir(*args, **kw)
diff --git a/paste/cgitb_catcher.py b/paste/cgitb_catcher.py
index 732f7e1..b417583 100644
--- a/paste/cgitb_catcher.py
+++ b/paste/cgitb_catcher.py
@@ -9,7 +9,6 @@ documentation for more:
import cgitb
from cStringIO import StringIO
import sys
-import traceback
class DummyFile(object):
pass
@@ -24,7 +23,7 @@ def middleware(application, **kw):
return started[0]
try:
- app_iter = application(environ, start_response)
+ app_iter = application(environ, detect_start_response)
return catching_iter(app_iter)
except:
if not started:
@@ -40,12 +39,12 @@ def middleware(application, **kw):
hook(*sys.exc_info())
return [dummy_file.getvalue()]
- def catching_iter(iter):
- if not iter:
+ def catching_iter(app_iter):
+ if not app_iter:
raise StopIteration
try:
- for v in iter:
- yield iter
+ for v in app_iter:
+ yield v
except:
exc = sys.exc_info()
dummy_file = StringIO()
diff --git a/paste/configmiddleware.py b/paste/configmiddleware.py
index bf4768a..6c64d6c 100644
--- a/paste/configmiddleware.py
+++ b/paste/configmiddleware.py
@@ -1,4 +1,3 @@
-from paste.util import threadinglocal
from paste import CONFIG
from paste import wsgilib
diff --git a/paste/errormiddleware.py b/paste/errormiddleware.py
index d5c2b02..f3ef73d 100644
--- a/paste/errormiddleware.py
+++ b/paste/errormiddleware.py
@@ -73,26 +73,25 @@ class ErrorMiddleware(object):
start_response('500 Internal Server Error',
[('content-type', 'text/html')])
# @@: it would be nice to deal with bad content types here
- dummy_file = StringIO()
response = self.exception_handler(sys.exc_info(), environ)
return [response]
- def catching_iter(self, iter, environ):
+ def catching_iter(self, app_iter, environ):
__traceback_supplement__ = Supplement, self, environ
- if not iter:
+ if not app_iter:
raise StopIteration
error_on_close = False
try:
- for v in iter:
+ for v in app_iter:
yield v
- if hasattr(iter, 'close'):
+ if hasattr(app_iter, 'close'):
error_on_close = True
- iter.close()
+ app_iter.close()
except:
response = self.exception_handler(sys.exc_info(), environ)
- if not error_on_close and hasattr(iter, 'close'):
+ if not error_on_close and hasattr(app_iter, 'close'):
try:
- iter.close()
+ app_iter.close()
except:
close_response = self.exception_handler(
sys.exc_info(), environ)
@@ -200,9 +199,9 @@ def handle_exception(exc_info, conf, error_stream, html=True):
error_stream.write(extra_data)
return return_error
-def send_report(reporter, exc_data, html=True):
+def send_report(rep, exc_data, html=True):
try:
- reporter.report(exc_data)
+ rep.report(exc_data)
except:
output = StringIO()
traceback.print_exc(file=output)
@@ -212,11 +211,11 @@ def send_report(reporter, exc_data, html=True):
<pre>%s</pre>
</p>""" % (
- cgi.escape(str(reporter)), output.getvalue())
+ cgi.escape(str(rep)), output.getvalue())
else:
return (
"Additionally an error occurred while sending the "
- "%s report:\n%s" % (str(reporter), output.getvalue()))
+ "%s report:\n%s" % (str(rep), output.getvalue()))
else:
return ''
diff --git a/paste/gzipper.py b/paste/gzipper.py
index 3bf42bb..50e9e48 100644
--- a/paste/gzipper.py
+++ b/paste/gzipper.py
@@ -5,7 +5,6 @@ Gzip-encodes the response.
"""
import gzip
-from cStringIO import StringIO
import wsgilib
class GzipOutput(object):
diff --git a/paste/httpexceptions.py b/paste/httpexceptions.py
index 7540a17..01d68f5 100644
--- a/paste/httpexceptions.py
+++ b/paste/httpexceptions.py
@@ -218,7 +218,7 @@ def middleware(application):
return start_response(status, headers, exc_info)
try:
- return application(environ, start_response)
+ return application(environ, checked_start_response)
except HTTPException, e:
if app_started:
# They've already started the response, so we can't
diff --git a/paste/lint.py b/paste/lint.py
index 0eac637..a52a227 100644
--- a/paste/lint.py
+++ b/paste/lint.py
@@ -24,7 +24,8 @@ def middleware(application):
start_response_started = []
def start_response_wrapper(*args, **kw):
- assert len(args) == 2 or len(args) == 3, "Invalid number of arguments: %s" % args
+ assert len(args) == 2 or len(args) == 3, (
+ "Invalid number of arguments: %s" % args)
assert not kw, "No keyword arguments allowed"
status = args[0]
headers = args[1]
@@ -47,8 +48,8 @@ def middleware(application):
iterator = application(environ, start_response_wrapper)
assert start_response_started, (
"The application returned, but did not call start_response()")
- assert iterator is not None and iterator != False, \
- "The application must return an iterator, if only an empty list"
+ assert iterator is not None and iterator != False, (
+ "The application must return an iterator, if only an empty list")
check_iterator(iterator)
@@ -121,7 +122,7 @@ class WriteWrapper:
class PartialIteratorWrapper:
def __init__(self, wsgi_iterator):
- self.iterator = iterator
+ self.iterator = wsgi_iterator
def __iter__(self):
# We want to make sure __iter__ is called
@@ -138,8 +139,8 @@ class IteratorWrapper:
return self
def next(self):
- assert not self.closed, \
- "Iterator read after closed"
+ assert not self.closed, (
+ "Iterator read after closed")
return self.iterator.next()
def close(self):
@@ -149,90 +150,104 @@ class IteratorWrapper:
def __del__(self):
if not self.closed:
- sys.stderr.write("Iterator garbage collected without being closed")
- assert self.closed, \
- "Iterator garbage collected without being closed"
+ sys.stderr.write(
+ "Iterator garbage collected without being closed")
+ assert self.closed, (
+ "Iterator garbage collected without being closed")
def check_environ(environ):
- assert type(environ) is DictType, \
- "Environment is not of the right type: %r (environment: %r)" % (type(environ), environ)
+ assert type(environ) is DictType, (
+ "Environment is not of the right type: %r (environment: %r)"
+ % (type(environ), environ))
for key in ['REQUEST_METHOD', 'SERVER_NAME', 'SERVER_PORT',
'wsgi.version', 'wsgi.input', 'wsgi.errors',
'wsgi.multithread', 'wsgi.multiprocess',
'wsgi.run_once']:
- assert environ.has_key(key), \
- "Environment missing required key: %r" % key
+ assert environ.has_key(key), (
+ "Environment missing required key: %r" % key)
for key in environ.keys():
if '.' in key:
# Extension, we don't care about its type
continue
- assert type(environ[key]) is StringType, \
- "Environmental variable %s is not a string: %r (value: %r)" % (type(environ[key]), environ[key])
+ assert type(environ[key]) is StringType, (
+ "Environmental variable %s is not a string: %r (value: %r)"
+ % (type(environ[key]), environ[key]))
- assert type(environ['wsgi.version']) is TupleType, \
- "wsgi.version should be a tuple (%r)" % environ['wsgi.version']
- assert environ['wsgi.url_scheme'] in ('http', 'https'), \
- "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme']
+ assert type(environ['wsgi.version']) is TupleType, (
+ "wsgi.version should be a tuple (%r)" % environ['wsgi.version'])
+ assert environ['wsgi.url_scheme'] in ('http', 'https'), (
+ "wsgi.url_scheme unknown: %r" % environ['wsgi.url_scheme'])
check_input(environ['wsgi.input'])
check_errors(environ['wsgi.errors'])
# @@: these need filling out:
- assert environ['REQUEST_METHOD'] in ('GET', 'HEAD', 'POST'), "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD']
+ assert environ['REQUEST_METHOD'] in ('GET', 'HEAD', 'POST'), (
+ "Unknown REQUEST_METHOD: %r" % environ['REQUEST_METHOD'])
assert (not environ.get('SCRIPT_NAME')
- or environ['SCRIPT_NAME'].startswith('/')), \
- "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME']
+ or environ['SCRIPT_NAME'].startswith('/')), (
+ "SCRIPT_NAME doesn't start with /: %r" % environ['SCRIPT_NAME'])
assert (not environ.get('PATH_INFO')
- or environ['PATH_INFO'].startswith('/')), \
- "PATH_INFO doesn't start with /: %s" % environ['PATH_INFO']
+ or environ['PATH_INFO'].startswith('/')), (
+ "PATH_INFO doesn't start with /: %s" % environ['PATH_INFO'])
if environ.get('CONTENT_LENGTH'):
- assert int(environ['CONTENT_LENGTH']) >= 0, "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH']
+ assert int(environ['CONTENT_LENGTH']) >= 0, (
+ "Invalid CONTENT_LENGTH: %r" % environ['CONTENT_LENGTH'])
if not environ.get('SCRIPT_NAME'):
- assert environ.has_key('PATH_INFO'), \
- "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO should at least be '/' if SCRIPT_NAME is empty)"
- assert environ.get('SCRIPT_NAME') != '/', \
- "SCRIPT_NAME cannot be '/'; it should instead be '', and PATH_INFO should be '/'"
+ assert environ.has_key('PATH_INFO'), (
+ "One of SCRIPT_NAME or PATH_INFO are required (PATH_INFO "
+ "should at least be '/' if SCRIPT_NAME is empty)")
+ assert environ.get('SCRIPT_NAME') != '/', (
+ "SCRIPT_NAME cannot be '/'; it should instead be '', and "
+ "PATH_INFO should be '/'")
def check_input(wsgi_input):
for attr in ['read', 'readline', 'readlines', '__iter__']:
- assert hasattr(wsgi_input, attr), \
- "wsgi.input (%r) doesn't have the attribute %s" % (wsgi_input, attr)
+ assert hasattr(wsgi_input, attr), (
+ "wsgi.input (%r) doesn't have the attribute %s"
+ % (wsgi_input, attr))
def check_errors(wsgi_errors):
for attr in ['flush', 'write', 'writelines']:
- assert hasattr(wsgi_errors, attr), \
- "wsgi.errors (%r) doesn't have the attributes %s" % (wsgi_errors, attr)
+ assert hasattr(wsgi_errors, attr), (
+ "wsgi.errors (%r) doesn't have the attribute %s"
+ % (wsgi_errors, attr))
def check_status(status):
- assert type(status) is StringType, \
- "Status must be a string (not %r)" % status
+ assert type(status) is StringType, (
+ "Status must be a string (not %r)" % status)
# Implicitly check that we can turn it into an integer:
status_int = int(status.split(None, 1)[0])
assert status_int >= 100, "Status code is invalid: %r" % status_int
def check_headers(headers):
- assert type(headers) is ListType, \
- "Headers (%r) must be of type list: %r" % (headers, type(headers))
+ assert type(headers) is ListType, (
+ "Headers (%r) must be of type list: %r"
+ % (headers, type(headers)))
header_names = {}
for item in headers:
- assert type(item) is TupleType, \
- "Individual headers (%r) must be of type tuple: %r" % (item, type(item))
+ assert type(item) is TupleType, (
+ "Individual headers (%r) must be of type tuple: %r"
+ % (item, type(item)))
assert len(item) == 2
name, value = item
- assert name.lower() != 'status', \
- "The Status header cannot be used; it conflicts with CGI script, and HTTP status is not given through headers (value: %r)." % value
+ assert name.lower() != 'status', (
+ "The Status header cannot be used; it conflicts with CGI "
+ "script, and HTTP status is not given through headers "
+ "(value: %r)." % value)
header_names[name.lower()] = None
- assert '\n' not in name and ':' not in name, \
- "Header names may not contain ':' or '\\n': %r" % name
+ assert '\n' not in name and ':' not in name, (
+ "Header names may not contain ':' or '\\n': %r" % name)
assert header_re.search(name), "Bad header name: %r" % name
- assert not name.endswith('-') and not name.endswith('_'), \
- "Names may not end in '-' or '_': %r" % name
- assert not bad_header_value_re.search(value), \
- "Bad header value: %r (bad char: %r)" % (value, bad_header_value_re.search(value).group(0))
+ assert not name.endswith('-') and not name.endswith('_'), (
+ "Names may not end in '-' or '_': %r" % name)
+ assert not bad_header_value_re.search(value), (
+ "Bad header value: %r (bad char: %r)"
+ % (value, bad_header_value_re.search(value).group(0)))
def check_content_type(status, headers):
code = int(status.split(None, 1)[0])
@@ -248,12 +263,14 @@ def check_content_type(status, headers):
assert 0, "No Content-Type header found in headers (%s)" % headers
def check_exc_info(exc_info):
- assert not exc_info or type(exc_info) is type(()), "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info))
+ assert not exc_info or type(exc_info) is type(()), (
+ "exc_info (%r) is not a tuple: %r" % (exc_info, type(exc_info)))
# More exc_info checks?
def check_iterator(iterator):
# Technically a string is legal, which is why it's a really bad
# idea, because it may cause the response to be returned
# character-by-character
- assert not isinstance(iterator, str), \
- "You should not return a string as your application iterator, instead return a single-item list containing that string."
+ assert not isinstance(iterator, str), (
+ "You should not return a string as your application iterator, "
+ "instead return a single-item list containing that string.")
diff --git a/paste/pycgiwrapper.py b/paste/pycgiwrapper.py
index eca2102..f95ad50 100644
--- a/paste/pycgiwrapper.py
+++ b/paste/pycgiwrapper.py
@@ -66,7 +66,7 @@ class CGIWrapper(object):
else:
del message['status']
headers = message.items()
- writer = start_response(status, headers)
+ start_response(status, headers)
return [body]
suffix_info = [t for t in imp.get_suffixes() if t[0] == '.py'][0]
@@ -74,8 +74,8 @@ class CGIWrapper(object):
def run_script(self):
f = open(self.cgi_filename, self.suffix_info[1])
try:
- mod = imp.load_module('__main__', f, self.cgi_filename,
- self.suffix_info)
+ imp.load_module('__main__', f, self.cgi_filename,
+ self.suffix_info)
except SystemExit:
pass
f.close()
@@ -144,7 +144,8 @@ _real_FieldStorage = cgi.FieldStorage
class FieldStorageWrapper(_real_FieldStorage):
def __init__(self, fp=None, headers=None, outerboundary="",
- environ=os.environ, keep_blank_values=0, strict_parsing=0):
+ environ=os.environ, keep_blank_values=0,
+ strict_parsing=0):
if fp is None:
# @@: Should I look for sys.stdin too?
# Or should I be replacing sys.stdin entirely?
diff --git a/paste/pyconfig.py b/paste/pyconfig.py
index d798f6e..d0192c6 100644
--- a/paste/pyconfig.py
+++ b/paste/pyconfig.py
@@ -141,8 +141,13 @@ class Config(UserDict.DictMixin):
self.namespaces.insert(0, d)
def load_commandline(self, *args, **kw):
+ if 'default' in kw:
+ default = kw['default']
+ del kw['default']
+ else:
+ default = False
options, args = parse_commandline(*args, **kw)
- self.load_dict(options)
+ self.load_dict(options, default=default)
return args
def update_sys_path(self):
@@ -181,7 +186,7 @@ def update_sys_path(paths, verbose):
print 'Adding %s to path' % path
sys.path.insert(0, path)
-def parse_commandline(items, bool_options, aliases={}, default=False):
+def parse_commandline(items, bool_options, aliases={}):
"""
Parses options from the command line. bool_options take no
arguments, everything else is supposed to take arguments. aliases
@@ -268,8 +273,7 @@ def convert_commandline(value):
try:
return int(value)
except ValueError:
- pass
- return value
+ return value
class DispatchingConfig(object):
@@ -342,7 +346,7 @@ class DispatchingConfig(object):
self._process_configs.append(conf)
def pop_process_config(self, conf=None):
- self._pop_from(self._process_config, conf)
+ self._pop_from(self._process_configs, conf)
def __getattr__(self, attr):
conf = self.current_conf()
diff --git a/paste/recursive.py b/paste/recursive.py
index 5c370b8..68bc380 100644
--- a/paste/recursive.py
+++ b/paste/recursive.py
@@ -50,7 +50,9 @@ class Recursive(object):
environ['paste.recursive.previous_environ'] = self.previous_environ
base_path = self.original_environ.get('SCRIPT_NAME')
if path.startswith('/'):
- assert path.startswith(base_path), "You can only forward requests to resources under the path %r (not %r)" % (base_path, path)
+ assert path.startswith(base_path), (
+ "You can only forward requests to resources under the "
+ "path %r (not %r)" % (base_path, path))
path = path[len(base_path)+1:]
assert not path.startswith('/')
path_info = '/' + path
@@ -66,13 +68,11 @@ class Recursive(object):
class Forwarder(Recursive):
def activate(self, environ):
- environ['wsgi.errors'].write('Forwarding to %r\n' % (environ['SCRIPT_NAME'] + environ['PATH_INFO']))
return self.application(environ, self.start_response)
class Includer(Recursive):
def activate(self, environ):
- environ['wsgi.errors'].write('Including %r\n' % (environ['SCRIPT_NAME'] + environ['PATH_INFO']))
response = IncludedResponse
def start_response(status, headers, exc_info=None):
if exc_info:
@@ -104,7 +104,9 @@ class IncludedResponse(object):
self.output = None
def write(self):
- assert self.output is not None, "This response has already been closed and no further data can be written."
+ assert self.output is not None, (
+ "This response has already been closed and no further data "
+ "can be written.")
self.output.write()
def __str__(self):
diff --git a/paste/reloader.py b/paste/reloader.py
index 72148e1..f2d75ba 100644
--- a/paste/reloader.py
+++ b/paste/reloader.py
@@ -63,7 +63,7 @@ class Monitor:
def check_reload(self):
filenames = self.extra_files[:]
- for name, module in sys.modules.items():
+ for module in sys.modules.values():
try:
filenames.append(module.__file__)
except AttributeError:
@@ -95,22 +95,3 @@ class Monitor:
watch_file = classinstancemethod(watch_file)
watch_file = Monitor.watch_file
-
-def awake_select(addrs):
- """
- When using socket.select(), processes will not quit. By connecting
- to the addresses locally we move the code out of the select, where
- it can terminate properly.
-
- (For now, KeyboardInterrupt seems to terminate these selects
- properly)
- """
-
- for addr in addrs:
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- sock.connect(addr)
- sock.close()
- except:
- pass
-
diff --git a/paste/server.py b/paste/server.py
index 0d147ec..b018384 100755
--- a/paste/server.py
+++ b/paste/server.py
@@ -50,7 +50,6 @@ if os.path.dirname(here) != paste_path:
'out of %s\n' % (here, paste_path))
from paste import reloader
-from paste import wsgilib
from paste import CONFIG
from paste.util import plugin
from paste import pyconfig
diff --git a/paste/tests/fixture.py b/paste/tests/fixture.py
index a6245e2..45b22a1 100644
--- a/paste/tests/fixture.py
+++ b/paste/tests/fixture.py
@@ -5,14 +5,13 @@ import mimetypes
import time
import cgi
import os
-import warnings
import webbrowser
+import smtplib
from Cookie import SimpleCookie
try:
from cStringIO import StringIO
except ImportError:
from StringIO import StringIO
-import types
import re
#from py.test.collect import Module, PyCollector
from paste.util import thirdparty
@@ -225,7 +224,8 @@ class FakeFile(object):
def open(self, mode):
if mode == 'r' or mode == 'rb':
if self.content is None:
- raise IOError("[FakeFS] No such file or directory: %r" % filename)
+ raise IOError("[FakeFS] No such file or directory: %r"
+ % self.filename)
return ReaderFile(self)
elif mode == 'w' or mode == 'wb':
return WriterFile(self)
@@ -234,8 +234,8 @@ class FakeFile(object):
class ReaderFile(object):
- def __init__(self, file):
- self.file = file
+ def __init__(self, fp):
+ self.file = fp
self.stream = StringIO(self.file.content)
self.open = True
@@ -249,8 +249,8 @@ class ReaderFile(object):
class WriterFile(object):
- def __init__(self, file):
- self.file = file
+ def __init__(self, fp):
+ self.file = fp
self.stream = StringIO()
self.open = True
@@ -317,6 +317,8 @@ class TestApp(object):
environ['CONTENT_LENGTH'] = str(len(params))
environ['REQUEST_METHOD'] = 'POST'
environ['wsgi.input'] = StringIO(params)
+ for header, value in headers.items():
+ environ['HTTP_%s' % header.replace('-', '_').upper()] = value
req = TestRequest(url, environ)
return self.do_request(req, status=status)
@@ -353,8 +355,9 @@ class TestApp(object):
if len(file_info) == 2:
# It only has a filename
filename = file_info[2]
- if self.conf.get('test_file_path'):
- filename = os.path.join(self.conf['test_file_path'], filename)
+ if self.config.get('test_file_path'):
+ filename = os.path.join(self.config['test_file_path'],
+ filename)
f = open(filename, 'rb')
content = f.read()
f.close()
diff --git a/paste/threaded.py b/paste/threaded.py
deleted file mode 100644
index 6abbd32..0000000
--- a/paste/threaded.py
+++ /dev/null
@@ -1,436 +0,0 @@
-# Note, this is totally incomplete and untested
-import threading
-import marshal
-import Queue
-import select
-import socket
-import errno
-import logging
-import atexit
-import BaseHTTPServer
-
-__version__ = '0.1'
-
-logger = logging.getLogger('wsgiserver.threaded')
-errorLog = logging.getLogger('wsgiserver.apperrors')
-
-intLength = len(marshal.dumps(int(1)))
-
-server = None
-
-class NotEnoughDataError(Exception):
- pass
-
-class ProtocolError(Exception):
- pass
-
-class ThreadedWSGIServer(object):
-
- def __init__(self, application):
- self.application = application
- threadCount = self.setting('StartServerThreads')
- self._maxServerThreads = self.setting('MaxServerThreads')
- self._minServerThreads = self.setting('MinServerThreads')
- self._threadPool = []
- self._threadCount = 0
- self._threadUseCounter = []
- self._requestQueue = Queue.Queue(self._maxServerThreads * 2)
- self._addr = {}
- # @@: Should load persistently
- self._requestID = 0
-
- logger.info('Creating %i threads' % threadCount)
- for i in range(threadCount):
- self.spawnThread()
-
- #self.recordPID() @@: ?
-
- self._socketHandlers = {}
- self._handlerCache = {}
- self._sockets = {}
-
- self.addSocketHandlers()
- self.running = True
- atexit.register(self.awakeSelect)
- atexit.register(self.shutdown)
- self.readyForRequests()
-
- def addSocketHandler(self, handlerClass, serverAddress=None):
- """
- Adds a socket handler for `serverAddress`, which is typically
- a tuple ``(host, port)``.
- """
- if serverAddress is None:
- serverAddress = self.address(handlerClass.defaultServerAddress())
- self._socketHandlers[serverAddress] = handlerClass
- self._handlerCache[serverAddress] = []
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- sock.bind(serverAddress)
- sock.listen(1024)
- self._sockets[serverAddress] = sock
- logger.info('Listening on: %s' % serverAddress)
-
- def readyForRequests(self):
- logger.info('Ready for requests')
-
- def spawnThread(self):
- """
- Create a new worker thread; threads run the `threadLoop`
- method.
- """
- t = threading.Thread(target=self.threadLoop)
- t.processing = False
- self._threadPool.append(t)
- self._threadCount += 1
- t.start()
- logger.info('New thread spawned, threadcount=%s' %
- self._threadCount)
-
- def absorbThread(self, count=1):
- """
- Absorb a thread.
- """
- for i in range(count):
- self._requestQueue.put(None)
- self._threadCount -= 1
- for t in self._threadPool:
- if not t.isAlive():
- rv = i.join()
- self._threadPool.remove(i)
- logger.info('Thread absorbed, threadcount=%s' %
- len(self.threadPool))
-
- def threadLoop(self):
- self.initThread()
- t = threading.currentThread()
- t.processing = False
- try:
- while 1:
- try:
- handler = self._requestQueue.get()
- # Non means time to quit
- if handler is None:
- break
- t.processing = True
- try:
- handler.handleRequest()
- except:
- logger.exception()
- handler.close()
- t.processing = False
- except Queue.Empty:
- pass
- finally:
- self.delThread()
-
- def initThread(self):
- pass
-
- def delThread(self):
- pass
-
- def awakeSelect(self):
- """
- The ``select()`` in `mainloop` is blocking, so when
- we shut down we have to make a connect to unblock it.
- Here's where we do that, called `shutDown`.
- """
-
- for addr in self._sockets.keys():
- sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- try:
- sock.connect(addr)
- sock.close()
- except:
- pass
-
- def shutdown(self):
- self.running = False
-
- def run(self, timeout=1):
- while 1:
- if not self.running:
- return
-
- try:
- input, output, exc = select.select(
- self._sockets.values(), [], [], timeout)
- except select.error, v:
- if v[0] == errno.EINTR or v[0] == 0:
- break
- else:
- raise
-
- for sock in input:
- self._requestID += 1
- client, addr = sock.accept()
- serverAddress = sock.getsockname()
- try:
- handler = self._handlerCache[serverAddress].pop()
- except IndexError:
- handler = self._socketHandlers[serverAddress](self, serverAddress)
- handler.activate(client, self._requestID)
- self._requestQueue.put(handler)
-
-class Handler(object):
-
- def __init__(self, server, serverAddress):
- self.server = server
- self.serverAddress = serverAddress
-
- def active(self, sock, requestID):
- self.requestID = requestID
- self.sock = sock
-
- def close(self):
- self.sock = None
- self.server._handlerCache[self._serverAddress].append(self)
-
- def handleRequest(self):
- raise NotImplementedError
-
-class ModWebKitHandler(Handler):
-
- protocolName = 'webkit'
-
- def receiveDict(self):
- """
- Utility function to receive a marshalled dictionary from
- the socket. Returns None if the request was empty.
- """
- chunk = ''
- missing = intLength
- while missing > 0:
- block = self.sock.recv(missing)
- if not block:
- self.sock.close()
- if len(chunk) == 0:
- # We probably awakened due to awakeSelect being called.
- return None
- else:
- # We got a partial request -- something went wrong.
- raise NotEnoughDataError, 'received only %d of %d bytes when receiving dictLength' % (len(chunk), intLength)
- chunk += block
- missing = intLength - len(chunk)
- try:
- dictLength = loads(chunk)
- except ValueError:
- logger.warn('bad marshal data for webkit adapter interface; '
- 'you can only connect to %s via an adapter, like '
- 'mod_webkit or wkcgi, not with a browser'
- % self._serverAddress[1])
- raise
- if type(dictLength) != type(1):
- self.sock.close()
- raise ProtocolError, "Invalid AppServer protocol"
- chunk = ''
- missing = dictLength
- while missing > 0:
- block = self.sock.recv(missing)
- if not block:
- self.sock.close()
- raise NotEnoughDataError, 'received only %d of %d bytes when receiving dict' % (len(chunk), dictLength)
- chunk += block
- missing = dictLength - len(chunk)
- return loads(chunk)
-
- def defaultServerAddress(cls):
- return ('127.0.0.1', 8086)
- defaultServerAddress = classmethod(defaultServerAddress)
-
- def handleRequest(self):
- data = []
- environ = self.receiveDict()
- if not environ:
- return
- if environ.get('REQUEST_URI'):
- requestURI = environ['REQUEST_URI']
- else:
- requestURI = environ.get('SCRIPT_NAME', '') + environ.get('PATH_INFO', '')
- query = environ.get('QUERY_STRING')
- if query:
- requestURI += '?' + query
- environ['wsgi.input'] = self.sock.makefile('rb', 8012)
- environ['wsgi.errors'] = LoggingError(errorLog)
- environ['wsgi.version'] = '1.0'
- environ['wsgi.multithread'] = True
- environ['wsgi.multiprocess'] = False
- output = WebKitStreamOut(self.sock)
-
- def start(status, headers):
- output.write('Status: %s\n' % status)
- for header, value in headers.items():
- assert '\n' not in value and '\r' not in value, \
- "Headers cannot contain newlines (%s: %r)" \
- % (header, value)
- assert ':' not in header, \
- "Headers should not container ':' (%r)" % header
- output.write('%s: %s\n' % (key, value))
- return output.write
-
- try:
- result = self.server.application(environ, start)
- if result:
- try:
- for data in result:
- output.write(data)
- finally:
- if hasattr(result, 'close'):
- result.close()
- except:
- errorLog.exception()
-
- output.close()
- try:
- self.sock.shutdown(1)
- self.sock.close()
- except:
- # @@: Why the except:?
- pass
-
-class LoggingError(object):
-
- def __init__(self, logger):
- self.logger = logger
-
- def flush(self):
- pass
-
- def write(self, s):
- self.logger.error(s)
-
- def writelines(self, seq):
- for s in seq:
- self.write(s)
-
-class WebKitStreamOut(object):
-
- def __init__(self, sock):
- self.sock = sock
-
- def write(self, s):
- self.sock.send(s)
-
-############################################################
-## HTTP
-############################################################
-
-
-class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
- """Handles incoming requests. Recreated with every request.
- Abstract base class.
- """
-
- ## This sends certain CGI variables. These are some that
- ## should be sent, but aren't:
- ## SERVER_ADDR
- ## SERVER_PORT
- ## SERVER_SOFTWARE
- ## SERVER_NAME
- ## HTTP_CONNECTION
- ## SERVER_PROTOCOL
- ## HTTP_KEEP_ALIVE
-
- ## These I don't think are needed:
- ## DOCUMENT_ROOT
- ## PATH_TRANSLATED
- ## GATEWAY_INTERFACE
- ## PATH
- ## SERVER_SIGNATURE
- ## SCRIPT_FILENAME (?)
- ## SERVER_ADMIN (?)
-
- server_version = 'WSGIServer/%s' % __version__
-
- def handleRequest(self):
- """
- Actually performs the request, creating the environment and
- calling self.doTransaction(env, myInput) to perform the
- response.
- """
- self.server_version = 'Webware/0.1'
- env = {}
- if self.headers.has_key('Content-Type'):
- env['CONTENT_TYPE'] = self.headers['Content-Type']
- del self.headers['Content-Type']
- self.headersToEnviron(self.headers, env)
- env['REMOTE_ADDR'], env['REMOTE_PORT'] = map(str, self.client_address)
- env['REQUEST_METHOD'] = self.command
- path = self.path
- if path.find('?') != -1:
- # @@: should REQUEST_URI include QUERY_STRING?
- env['REQUEST_URI'], env['QUERY_STRING'] = path.split('?', 1)
- else:
- env['REQUEST_URI'] = path
- env['QUERY_STRING'] = ''
- env['PATH_INFO'] = env['REQUEST_URI']
- env['SCRIPT_NAME'] = ''
- myInput = ''
- if self.headers.has_key('Content-Length'):
- myInput = self.rfile.read(int(self.headers['Content-Length']))
- self.doTransaction(env, myInput)
-
- do_GET = do_POST = do_HEAD = handleRequest
- # These methods are used in WebDAV requests:
- do_OPTIONS = do_PUT = do_DELETE = handleRequest
- do_MKCOL = do_COPY = do_MOVE = handleRequest
- do_PROPFIND = handleRequest
-
- def headersToEnviron(self, headers, env):
- """Use a simple heuristic to convert all the headers to
- environmental variables..."""
- for header, value in headers.items():
- env['HTTP_%s' % (header.upper().replace('-', '_'))] = value
- return env
-
- def processResponse(self, data):
- """
- Takes a string (like what a CGI script would print) and
- sends the actual HTTP response (response code, headers, body).
- """
- s = StringIO(data)
- headers = mimetools.Message(s)
- self.sendStatus(headers)
- self.sendHeaders(headers)
- self.sendBody(s)
-
- def sendStatus(self, status):
- status = str(status)
- pos = status.find(' ')
- if pos == -1:
- code = int(status)
- message = ''
- else:
- code = int(status[:pos])
- message = status[pos:].strip()
- self.send_response(code, message)
-
- def sendHeaders(self, headers):
- for header, value in headers.items():
- self.send_header(header, value)
- self.end_headers()
-
- def sendBody(self, bodyFile):
- self.wfile.write(bodyFile.read())
- bodyFile.close()
-
- def log_message(self, format, *args):
- self.server.logMessage(format % args)
-
- def log_request(self, *args, **kw):
- pass
-
-
-class HTTPHandler(BaseHTTPServer.BaseHTTPRequestHandler):
-
- protocolName = 'http'
-
- def defaultServerAddress(cls):
- # @@: 127.0.0.1 isn't very useful
- return ('127.0.0.1', 80)
- defaultServerAddress = classmethod(defaultServerAddress)
-
- def handleRequest(self):
- baseHandler = BaseHTTPHandler(req, None, self)
-
diff --git a/paste/urlparser.py b/paste/urlparser.py
index 89a1fca..4e2eaf1 100644
--- a/paste/urlparser.py
+++ b/paste/urlparser.py
@@ -175,7 +175,8 @@ class URLParser(object):
environ,
status,
'''
- <p>The resource has moved to <a href="%s">%s</a>. You should be redirected automatically.</p>''' % (url, url))
+ <p>The resource has moved to <a href="%s">%s</a>. You
+ should be redirected automatically.</p>''' % (url, url))
start_response(status, headers + [('Location', url)])
return [body]
diff --git a/paste/util/threadedprint.py b/paste/util/threadedprint.py
index a9ff7fd..eb57a01 100644
--- a/paste/util/threadedprint.py
+++ b/paste/util/threadedprint.py
@@ -65,8 +65,8 @@ class PrintCatcher(filemixin.FileMixin):
def __init__(self, default=None, factory=None, paramwriter=None):
assert len(filter(lambda x: x is not None,
- [default, factory, paramwriter])) <= 1, \
- "You can only provide one of default, factory, or paramwriter"
+ [default, factory, paramwriter])) <= 1, (
+ "You can only provide one of default, factory, or paramwriter")
if default:
self._defaultfunc = self._writedefault
elif factory:
@@ -99,7 +99,9 @@ class PrintCatcher(filemixin.FileMixin):
self._paramwriter(name, v)
def _writeerror(self, name, v):
- assert 0, "There is no PrintCatcher output stream for the thread %r" % name
+ assert False, (
+ "There is no PrintCatcher output stream for the thread %r"
+ % name)
def register(self, catcher, name=None,
currentThread=threading.currentThread):
@@ -111,7 +113,8 @@ class PrintCatcher(filemixin.FileMixin):
currentThread=threading.currentThread):
if name is None:
name = currentThread().getName()
- assert self._catchers.has_key(name), "There is no PrintCatcher catcher for the thread %r" % name
+ assert self._catchers.has_key(name), (
+ "There is no PrintCatcher catcher for the thread %r" % name)
del self._catchers[name]
_printcatcher = None
@@ -134,7 +137,9 @@ def uninstall():
deregister = not_installed_error
def not_installed_error(*args, **kw):
- assert 0, "threadedprint has not yet been installed (call threadedprint.install())"
+ assert False, (
+ "threadedprint has not yet been installed (call "
+ "threadedprint.install())")
register = deregister = not_installed_error
@@ -142,8 +147,8 @@ class StdinCatcher(filemixin.FileMixin):
def __init__(self, default=None, factory=None, paramwriter=None):
assert len(filter(lambda x: x is not None,
- [default, factory, paramwriter])) <= 1, \
- "You can only provide one of default, factory, or paramwriter"
+ [default, factory, paramwriter])) <= 1, (
+ "You can only provide one of default, factory, or paramwriter")
if default:
self._defaultfunc = self._readdefault
elif factory:
@@ -161,7 +166,7 @@ class StdinCatcher(filemixin.FileMixin):
name = currentThread().getName()
catchers = self._catchers
if not catchers.has_key(name):
- self._defaultfunc(name, v, size)
+ self._defaultfunc(name, size)
else:
catcher = catchers[name]
catcher.read(size)
@@ -176,7 +181,9 @@ class StdinCatcher(filemixin.FileMixin):
self._paramreader(name, size)
def _readerror(self, name, size):
- assert 0, "There is no StdinCatcher output stream for the thread %r" % name
+ assert False, (
+ "There is no StdinCatcher output stream for the thread %r"
+ % name)
def register(self, catcher, name=None,
currentThread=threading.currentThread):
@@ -188,7 +195,8 @@ class StdinCatcher(filemixin.FileMixin):
currentThread=threading.currentThread):
if name is None:
name = currentThread().getName()
- assert self._catchers.has_key(name), "There is no StdinCatcher catcher for the thread %r" % name
+ assert self._catchers.has_key(name), (
+ "There is no StdinCatcher catcher for the thread %r" % name)
del self._catchers[name]
_stdincatcher = None
@@ -210,4 +218,6 @@ def uninstall():
register_stdin = deregister_stdin = not_installed_error_stdin
def not_installed_error_stdin(*args, **kw):
- assert 0, "threadedprint has not yet been installed for stdin (call threadedprint.install_stdin())"
+ assert False, (
+ "threadedprint has not yet been installed for stdin (call "
+ "threadedprint.install_stdin())")
diff --git a/paste/wdg_validate.py b/paste/wdg_validate.py
index a7903d1..ad8ee46 100644
--- a/paste/wdg_validate.py
+++ b/paste/wdg_validate.py
@@ -27,10 +27,12 @@ class WDGValidateMiddleware(object):
def __call__(self, environ, start_response):
output = StringIO()
response = []
+
def writer_start_response(status, headers, exc_info=None):
response.extend((status, headers))
start_response(status, headers, exc_info)
return output.write
+
app_iter = self.app(environ, writer_start_response)
try:
for s in app_iter:
@@ -51,7 +53,13 @@ class WDGValidateMiddleware(object):
ops.append('--xml')
# @@: Should capture encoding too
conf = environ['paste.config']
- wdg_path = conf.get('wdg_path', 'validate')
+ html_errors = self.call_wdg_validate(
+ conf.get('wdg_path', 'validate'), ops, page)
+ if not html_errors:
+ return [page]
+ return self.add_error(page, html_errors)
+
+ def call_wdg_validate(self, wdg_path, ops, page):
proc = subprocess.Popen([wdg_path] + ops,
shell=False,
close_fds=True,
@@ -60,16 +68,16 @@ class WDGValidateMiddleware(object):
stderr=subprocess.STDOUT)
stdout = proc.communicate(page)[0]
proc.wait()
- if not stdout:
- return [page]
- add_text = '<pre style="background-color: #ffd; color: #600; border: 1px solid #000;">%s</pre>' % cgi.escape(stdout)
- match = self._end_body_regex.search(page)
+ return stdout
+
+ def add_error(self, html_page, html_errors):
+ add_text = ('<pre style="background-color: #ffd; color: #600; '
+ 'border: 1px solid #000;">%s</pre>'
+ % cgi.escape(html_errors))
+ match = self._end_body_regex.search(html_page)
if match:
- page = page[:match.start()] + add_text + page[match.end():]
+ return [html_page[:match.start()]
+ + add_text
+ + html_page[match.end():]]
else:
- page += add_text
- return [page]
-
-
-
-
+ return [html_page + add_text]
diff --git a/paste/wsgilib.py b/paste/wsgilib.py
index 3bf5a6b..9537e9d 100644
--- a/paste/wsgilib.py
+++ b/paste/wsgilib.py
@@ -118,10 +118,10 @@ def construct_url(environ, with_query_string=True, with_path_info=True):
if environ['wsgi.url_scheme'] == 'https':
if environ['SERVER_PORT'] != '443':
- url += ':' + environ['SERVER_PORT']
+ url += ':' + environ['SERVER_PORT']
else:
if environ['SERVER_PORT'] != '80':
- url += ':' + environ['SERVER_PORT']
+ url += ':' + environ['SERVER_PORT']
url += environ.get('SCRIPT_NAME','')
if with_path_info:
@@ -197,8 +197,8 @@ def send_file(filename):
class _FileIter:
- def __init__(self, file, blocksize=4096):
- self.file = file
+ def __init__(self, fp, blocksize=4096):
+ self.file = fp
self.blocksize = blocksize
def __iter__(self):
@@ -223,7 +223,7 @@ def has_header(headers, name):
return True
return False
-def header_value(headers, name, collapse=False):
+def header_value(headers, name):
"""
Returns the header's value, or None if no such header. If a
header appears more than once, all the values of the headers