summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc Abramowitz <marc@marc-abramowitz.com>2016-03-07 13:56:40 -0800
committerMarc Abramowitz <marc@marc-abramowitz.com>2016-03-07 13:56:40 -0800
commitac2c2ebe9088237fb5b3f3fd8c24b53d3ea94605 (patch)
treed257ee9f3ec398c41056ff7ce505eff583f5da50
parent8a98c4272d8d7dc723b3125dedc690fe5be58a44 (diff)
parent535e6df5251c2cc433e5c76e55b44f1832451d4e (diff)
downloadpaste-ac2c2ebe9088237fb5b3f3fd8c24b53d3ea94605.tar.gz
Merged in nilsph/paste/py3k (pull request #28)
Py3k fixes
-rw-r--r--paste/exceptions/collector.py2
-rw-r--r--paste/exceptions/formatter.py4
-rw-r--r--paste/fixture.py4
-rw-r--r--paste/request.py11
-rw-r--r--paste/util/template.py11
-rw-r--r--paste/wsgiwrappers.py3
-rwxr-xr-xtests/cgiapp_data/form.cgi59
-rw-r--r--tests/test_cgiapp.py23
-rw-r--r--tests/test_doctests.py5
-rw-r--r--tests/test_template.txt4
-rw-r--r--tests/test_wsgiwrappers.py2
11 files changed, 109 insertions, 19 deletions
diff --git a/paste/exceptions/collector.py b/paste/exceptions/collector.py
index 8867bf7..632ce06 100644
--- a/paste/exceptions/collector.py
+++ b/paste/exceptions/collector.py
@@ -266,7 +266,7 @@ class ExceptionCollector(object):
name = co.co_name
globals = f.f_globals
locals = f.f_locals
- if not hasattr(locals, 'has_key'):
+ if not hasattr(locals, 'keys'):
# Something weird about this frame; it's not a real dict
warnings.warn(
"Frame %s has an invalid locals(): %r" % (
diff --git a/paste/exceptions/formatter.py b/paste/exceptions/formatter.py
index c83ab50..09309de 100644
--- a/paste/exceptions/formatter.py
+++ b/paste/exceptions/formatter.py
@@ -217,7 +217,7 @@ class TextFormatter(AbstractFormatter):
elif isinstance(value, dict):
lines = ['\n', title, '-'*len(title)]
items = value.items()
- items.sort()
+ items = sorted(items)
for n, v in items:
try:
v = repr(v)
@@ -303,7 +303,7 @@ class HTMLFormatter(TextFormatter):
def zebra_table(self, title, rows, table_class="variables"):
if isinstance(rows, dict):
rows = rows.items()
- rows.sort()
+ rows = sorted(rows)
table = ['<table class="%s">' % table_class,
'<tr class="header"><th colspan="2">%s</th></tr>'
% self.quote(title)]
diff --git a/paste/fixture.py b/paste/fixture.py
index df1c75d..363f119 100644
--- a/paste/fixture.py
+++ b/paste/fixture.py
@@ -226,8 +226,8 @@ class TestApp(object):
if hasattr(params, 'items'):
# Some other multi-dict like format
params = urlencode(params.items())
- if six.PY3:
- params = params.encode('utf8')
+ if six.PY3 and isinstance(params, six.text_type):
+ params = params.encode('utf8')
if upload_files:
params = urlparse.parse_qsl(params, keep_blank_values=True)
content_type, params = self.encode_multipart(
diff --git a/paste/request.py b/paste/request.py
index f0d91c1..8d5e5c3 100644
--- a/paste/request.py
+++ b/paste/request.py
@@ -140,7 +140,7 @@ def parse_dict_querystring(environ):
environ['paste.parsed_dict_querystring'] = (multi, source)
return multi
-def parse_formvars(environ, include_get_vars=True):
+def parse_formvars(environ, include_get_vars=True, encoding=None, errors=None):
"""Parses the request, returning a MultiDict of form variables.
If ``include_get_vars`` is true then GET (query string) variables
@@ -182,9 +182,16 @@ def parse_formvars(environ, include_get_vars=True):
environ['CONTENT_TYPE'] = ''
else:
input = environ['wsgi.input']
+ kwparms = {}
+ if six.PY3:
+ if encoding:
+ kwparms['encoding'] = encoding
+ if errors:
+ kwparms['errors'] = errors
fs = cgi.FieldStorage(fp=input,
environ=environ,
- keep_blank_values=1)
+ keep_blank_values=1,
+ **kwparms)
environ['QUERY_STRING'] = old_query_string
if fake_out_cgi:
environ['CONTENT_TYPE'] = old_content_type
diff --git a/paste/util/template.py b/paste/util/template.py
index f0826af..5a63664 100644
--- a/paste/util/template.py
+++ b/paste/util/template.py
@@ -318,28 +318,27 @@ def html_quote(value):
if value is None:
return ''
if not isinstance(value, six.string_types):
- if hasattr(value, '__unicode__'):
+ if six.PY2 and hasattr(value, '__unicode__'):
value = unicode(value)
else:
value = str(value)
value = cgi.escape(value, 1)
- if isinstance(value, unicode):
+ if six.PY2 and isinstance(value, unicode):
value = value.encode('ascii', 'xmlcharrefreplace')
return value
def url(v):
if not isinstance(v, six.string_types):
- if hasattr(v, '__unicode__'):
+ if six.PY2 and hasattr(v, '__unicode__'):
v = unicode(v)
else:
v = str(v)
- if isinstance(v, unicode):
+ if six.PY2 and isinstance(v, unicode):
v = v.encode('utf8')
return quote(v)
def attr(**kw):
- kw = kw.items()
- kw.sort()
+ kw = sorted(kw.items())
parts = []
for name, value in kw:
if value is None:
diff --git a/paste/wsgiwrappers.py b/paste/wsgiwrappers.py
index 7b8f6de..674054f 100644
--- a/paste/wsgiwrappers.py
+++ b/paste/wsgiwrappers.py
@@ -199,7 +199,8 @@ class WSGIRequest(object):
GET = property(GET, doc=GET.__doc__)
def _POST(self):
- return parse_formvars(self.environ, include_get_vars=False)
+ return parse_formvars(self.environ, include_get_vars=False,
+ encoding=self.charset, errors=self.errors)
def POST(self):
"""Dictionary-like object representing the POST body.
diff --git a/tests/cgiapp_data/form.cgi b/tests/cgiapp_data/form.cgi
index 2181998..c4c562d 100755
--- a/tests/cgiapp_data/form.cgi
+++ b/tests/cgiapp_data/form.cgi
@@ -1,11 +1,68 @@
#!/usr/bin/env python
+from __future__ import print_function
+
import cgi
+import six
print('Content-type: text/plain')
print('')
-form = cgi.FieldStorage()
+if six.PY3:
+ # Python 3: cgi.FieldStorage keeps some field names as unicode and some as
+ # the repr() of byte strings, duh.
+
+ class FieldStorage(cgi.FieldStorage):
+
+ def _key_candidates(self, key):
+ yield key
+
+ try:
+ # assume bytes, coerce to str
+ try:
+ yield key.decode(self.encoding)
+ except UnicodeDecodeError:
+ pass
+ except AttributeError:
+ # assume str, coerce to bytes
+ try:
+ yield key.encode(self.encoding)
+ except UnicodeEncodeError:
+ pass
+
+ def __getitem__(self, key):
+
+ superobj = super(FieldStorage, self)
+
+ error = None
+
+ for candidate in self._key_candidates(key):
+ if isinstance(candidate, bytes):
+ # ouch
+ candidate = repr(candidate)
+ try:
+ return superobj.__getitem__(candidate)
+ except KeyError as e:
+ if error is None:
+ error = e
+
+ # fall through, re-raise the first KeyError
+ raise error
+
+ def __contains__(self, key):
+ superobj = super(FieldStorage, self)
+
+ for candidate in self._key_candidates(key):
+ if superobj.__contains__(candidate):
+ return True
+ return False
+
+else: # PY2
+
+ FieldStorage = cgi.FieldStorage
+
+
+form = FieldStorage()
print('Filename: %s' % form['up'].filename)
print('Name: %s' % form['name'].value)
diff --git a/tests/test_cgiapp.py b/tests/test_cgiapp.py
index 12cb2be..900e83e 100644
--- a/tests/test_cgiapp.py
+++ b/tests/test_cgiapp.py
@@ -8,6 +8,29 @@ data_dir = os.path.join(os.path.dirname(__file__), 'cgiapp_data')
# these CGI scripts can't work on Windows or Jython
if sys.platform != 'win32' and not sys.platform.startswith('java'):
+
+ # Ensure the CGI scripts are called with the same python interpreter. Put a
+ # symlink to the interpreter executable into the path...
+ def setup_module():
+ global oldpath, pyexelink
+ oldpath = os.environ.get('PATH', None)
+ os.environ['PATH'] = data_dir + os.path.pathsep + oldpath
+ pyexelink = os.path.join(data_dir, "python")
+ try:
+ os.unlink(pyexelink)
+ except OSError:
+ pass
+ os.symlink(sys.executable, pyexelink)
+
+ # ... and clean up again.
+ def teardown_module():
+ global oldpath, pyexelink
+ os.unlink(pyexelink)
+ if oldpath is not None:
+ os.environ['PATH'] = oldpath
+ else:
+ del os.environ['PATH']
+
def test_ok():
app = TestApp(CGIApplication({}, script='ok.cgi', path=[data_dir]))
res = app.get('')
diff --git a/tests/test_doctests.py b/tests/test_doctests.py
index 875fbc2..d59d666 100644
--- a/tests/test_doctests.py
+++ b/tests/test_doctests.py
@@ -1,3 +1,4 @@
+import six
import doctest
from paste.util.import_string import simple_import
import os
@@ -25,7 +26,9 @@ modules = [
'paste.request',
]
-options = doctest.ELLIPSIS|doctest.REPORT_ONLY_FIRST_FAILURE
+options = doctest.ELLIPSIS | doctest.REPORT_ONLY_FIRST_FAILURE
+if six.PY3:
+ options |= doctest.IGNORE_EXCEPTION_DETAIL
def test_doctests():
for filename in filenames:
diff --git a/tests/test_template.txt b/tests/test_template.txt
index 45a85e2..f3466f2 100644
--- a/tests/test_template.txt
+++ b/tests/test_template.txt
@@ -97,8 +97,8 @@ in Python, but it's more useful in templates generally)::
... elif item == 'orange':
... assert loop.last
... if loop.first_group(lambda i: i[0].upper()):
- ... print '%s:' % item[0].upper()
- ... print loop.number, item
+ ... print('%s:' % item[0].upper())
+ ... print("%s %s" % (loop.number, item))
A:
1 apple
2 asparagus
diff --git a/tests/test_wsgiwrappers.py b/tests/test_wsgiwrappers.py
index 8719693..75d03ed 100644
--- a/tests/test_wsgiwrappers.py
+++ b/tests/test_wsgiwrappers.py
@@ -13,7 +13,7 @@ class AssertApp(object):
def __call__(self, environ, start_response):
start_response('200 OK', [('Content-type','text/plain')])
self.assertfunc(environ)
- return ['Passed']
+ return [b'Passed']
no_encoding = object()
def valid_name(name, encoding=no_encoding, post=False):