summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcel Hellkamp <marc@gsites.de>2020-01-01 16:28:31 +0100
committerMarcel Hellkamp <marc@gsites.de>2020-01-01 16:28:31 +0100
commit45692af31e6acdcb4332fefb2c8313965a2ff574 (patch)
treec97dffe7816971a1294053812cbbbbc1728939d4
parentef156dbb3f040065bf021600c40cad34eb8b2046 (diff)
downloadbottle-45692af31e6acdcb4332fefb2c8313965a2ff574.tar.gz
Removed bottle.py3k flag and all python 2 only code.
-rwxr-xr-xbottle.py148
-rwxr-xr-xtest/test_environ.py22
-rw-r--r--test/test_route.py11
-rwxr-xr-xtest/test_wsgi.py3
-rwxr-xr-xtest/tools.py8
5 files changed, 65 insertions, 127 deletions
diff --git a/bottle.py b/bottle.py
index c52c20d..1ee8ceb 100755
--- a/bottle.py
+++ b/bottle.py
@@ -112,7 +112,8 @@ except ImportError:
py = sys.version_info
-py3k = py.major > 2
+if py < (3, 5, 0):
+ raise ImportError("Unsupported python version: %d.%d < 3.5.0" % (py.major, py.minor))
# Workaround for the "print is a keyword/function" Python 2/3 dilemma
@@ -123,41 +124,25 @@ except IOError:
_stdout = lambda x: sys.stdout.write(x)
_stderr = lambda x: sys.stderr.write(x)
-# Lots of stdlib and builtin differences.
-if py3k:
- import http.client as httplib
- import _thread as thread
- from urllib.parse import urljoin, SplitResult as UrlSplitResult
- from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
- urlunquote = functools.partial(urlunquote, encoding='latin1')
- from http.cookies import SimpleCookie, Morsel, CookieError
- from collections.abc import MutableMapping as DictMixin
- import pickle
- from io import BytesIO
- import configparser
-
- basestring = str
- unicode = str
- json_loads = lambda s: json_lds(touni(s))
- callable = lambda x: hasattr(x, '__call__')
- imap = map
-
- def _raise(*a):
- raise a[0](a[1]).with_traceback(a[2])
-else: # 2.x
- import httplib
- import thread
- from urlparse import urljoin, SplitResult as UrlSplitResult
- from urllib import urlencode, quote as urlquote, unquote as urlunquote
- from Cookie import SimpleCookie, Morsel, CookieError
- from itertools import imap
- import cPickle as pickle
- from StringIO import StringIO as BytesIO
- import ConfigParser as configparser
- from collections import MutableMapping as DictMixin
- unicode = unicode
- json_loads = json_lds
- exec(compile('def _raise(*a): raise a[0], a[1], a[2]', '<py3fix>', 'exec'))
+import http.client as httplib
+import _thread as thread
+from urllib.parse import urljoin, SplitResult as UrlSplitResult
+from urllib.parse import urlencode, quote as urlquote, unquote as urlunquote
+urlunquote = functools.partial(urlunquote, encoding='latin1')
+from http.cookies import SimpleCookie, Morsel, CookieError
+from collections.abc import MutableMapping as DictMixin
+import pickle
+from io import BytesIO
+import configparser
+
+basestring = str
+unicode = str
+json_loads = lambda s: json_lds(touni(s))
+callable = lambda x: hasattr(x, '__call__')
+imap = map
+
+def _raise(*a):
+ raise a[0](a[1]).with_traceback(a[2])
# Some helpers for string/byte handling
def tob(s, enc='utf8'):
@@ -172,7 +157,7 @@ def touni(s, enc='utf8', err='strict'):
return unicode("" if s is None else s)
-tonat = touni if py3k else tob
+tonat = touni
@@ -583,8 +568,8 @@ class Route(object):
""" Return the callback. If the callback is a decorated function, try to
recover the original function. """
func = self.callback
- func = getattr(func, '__func__' if py3k else 'im_func', func)
- closure_attr = '__closure__' if py3k else 'func_closure'
+ func = getattr(func, '__func__', func)
+ closure_attr = '__closure__'
while hasattr(func, closure_attr) and getattr(func, closure_attr):
attributes = getattr(func, closure_attr)
func = attributes[0].cell_contents
@@ -730,13 +715,12 @@ class Bottle(object):
def start_response(status, headerlist, exc_info=None):
if exc_info:
_raise(*exc_info)
- if py3k:
- # Errors here mean that the mounted WSGI app did not
- # follow PEP-3333 (which requires latin1) or used a
- # pre-encoding other than utf8 :/
- status = status.encode('latin1').decode('utf8')
- headerlist = [(k, v.encode('latin1').decode('utf8'))
- for (k, v) in headerlist]
+ # Errors here mean that the mounted WSGI app did not
+ # follow PEP-3333 (which requires latin1) or used a
+ # pre-encoding other than utf8 :/
+ status = status.encode('latin1').decode('utf8')
+ headerlist = [(k, v.encode('latin1').decode('utf8'))
+ for (k, v) in headerlist]
rs.status = status
for name, value in headerlist:
rs.add_header(name, value)
@@ -986,8 +970,7 @@ class Bottle(object):
def _handle(self, environ):
path = environ['bottle.raw_path'] = environ['PATH_INFO']
- if py3k:
- environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')
+ environ['PATH_INFO'] = path.encode('latin1').decode('utf8', 'ignore')
environ['bottle.app'] = self
request.bind(environ)
@@ -1412,9 +1395,8 @@ class BaseRequest(object):
if key in self.environ: safe_env[key] = self.environ[key]
args = dict(fp=self.body, environ=safe_env, keep_blank_values=True)
- if py3k:
- args['encoding'] = 'utf8'
- post.recode_unicode = False
+ args['encoding'] = 'utf8'
+ post.recode_unicode = False
data = cgi.FieldStorage(**args)
self['_cgi.FieldStorage'] = data #http://bugs.python.org/issue18394
data = data.list or []
@@ -1779,9 +1761,7 @@ class BaseResponse(object):
def _wsgi_status_line(self):
""" WSGI conform status line (latin1-encodeable) """
- if py3k:
- return self._status_line.encode('utf8').decode('latin1')
- return self._status_line
+ return self._status_line.encode('utf8').decode('latin1')
@property
def headerlist(self):
@@ -1797,8 +1777,7 @@ class BaseResponse(object):
if self._cookies:
for c in self._cookies.values():
out.append(('Set-Cookie', _hval(c.OutputString())))
- if py3k:
- out = [(k, v.encode('utf8').decode('latin1')) for (k, v) in out]
+ out = [(k, v.encode('utf8').decode('latin1')) for (k, v) in out]
return out
content_type = HeaderProperty('Content-Type')
@@ -2119,44 +2098,20 @@ class MultiDict(DictMixin):
def keys(self):
return self.dict.keys()
- if py3k:
-
- def values(self):
- return (v[-1] for v in self.dict.values())
-
- def items(self):
- return ((k, v[-1]) for k, v in self.dict.items())
+ def values(self):
+ return (v[-1] for v in self.dict.values())
- def allitems(self):
- return ((k, v) for k, vl in self.dict.items() for v in vl)
-
- iterkeys = keys
- itervalues = values
- iteritems = items
- iterallitems = allitems
-
- else:
+ def items(self):
+ return ((k, v[-1]) for k, v in self.dict.items())
- def values(self):
- return [v[-1] for v in self.dict.values()]
+ def allitems(self):
+ return ((k, v) for k, vl in self.dict.items() for v in vl)
- def items(self):
- return [(k, v[-1]) for k, v in self.dict.items()]
+ iterkeys = keys
+ itervalues = values
+ iteritems = items
+ iterallitems = allitems
- def iterkeys(self):
- return self.dict.iterkeys()
-
- def itervalues(self):
- return (v[-1] for v in self.dict.itervalues())
-
- def iteritems(self):
- return ((k, v[-1]) for k, v in self.dict.iteritems())
-
- def iterallitems(self):
- return ((k, v) for k, vl in self.dict.iteritems() for v in vl)
-
- def allitems(self):
- return [(k, v) for k, vl in self.dict.iteritems() for v in vl]
def get(self, key, default=None, index=-1, type=None):
""" Return the most recent value for a key.
@@ -2306,12 +2261,9 @@ class WSGIHeaderDict(DictMixin):
def __getitem__(self, key):
val = self.environ[self._ekey(key)]
- if py3k:
- if isinstance(val, unicode):
- val = val.encode('latin1').decode('utf8')
- else:
- val = val.decode('utf8')
- return val
+ if isinstance(val, unicode):
+ return val.encode('latin1').decode('utf8')
+ return val.decode('utf8')
def __setitem__(self, key, value):
raise TypeError("%s is read-only." % self.__class__)
@@ -2417,9 +2369,7 @@ class ConfigDict(dict):
"""
options.setdefault('allow_no_value', True)
- if py3k:
- options.setdefault('interpolation',
- configparser.ExtendedInterpolation())
+ options.setdefault('interpolation', configparser.ExtendedInterpolation())
conf = configparser.ConfigParser(**options)
conf.read(filename)
for section in conf.sections():
diff --git a/test/test_environ.py b/test/test_environ.py
index 908b9d8..598e4e0 100755
--- a/test/test_environ.py
+++ b/test/test_environ.py
@@ -501,15 +501,8 @@ class TestResponse(unittest.TestCase):
result = [v for (h, v) in rs.headerlist if h.lower()=='x-test'][0]
self.assertEqual(wire, result)
- if bottle.py3k:
- cmp(1, tonat('1', 'latin1'))
- cmp('öäü', 'öäü'.encode('utf8').decode('latin1'))
- # Dropped byte header support in Python 3:
- #cmp(tob('äöü'), 'äöü'.encode('utf8').decode('latin1'))
- else:
- cmp(1, '1')
- cmp('öäü', 'öäü')
- cmp(touni('äöü'), 'äöü')
+ cmp(1, tonat('1', 'latin1'))
+ cmp('öäü', 'öäü'.encode('utf8').decode('latin1'))
def test_set_status(self):
rs = BaseResponse()
@@ -581,12 +574,11 @@ class TestResponse(unittest.TestCase):
self.assertEqual(rs.status_line, '404 Brain not Found') # last value
# Unicode in status line (thanks RFC7230 :/)
- if bottle.py3k:
- rs.status = '400 Non-ASÎÎ'
- self.assertEqual(rs.status, rs.status_line)
- self.assertEqual(rs.status_code, 400)
- wire = rs._wsgi_status_line().encode('latin1')
- self.assertEqual(rs.status, wire.decode('utf8'))
+ rs.status = '400 Non-ASÎÎ'
+ self.assertEqual(rs.status, rs.status_line)
+ self.assertEqual(rs.status_code, 400)
+ wire = rs._wsgi_status_line().encode('latin1')
+ self.assertEqual(rs.status, wire.decode('utf8'))
def test_content_type(self):
rs = BaseResponse()
diff --git a/test/test_route.py b/test/test_route.py
index 9819d36..fb0d944 100644
--- a/test/test_route.py
+++ b/test/test_route.py
@@ -59,9 +59,8 @@ class TestRoute(unittest.TestCase):
# triggers the "TypeError: 'foo' is not a Python function"
self.assertEqual(set(route.get_callback_args()), set(['a', 'b']))
- if bottle.py3k:
- def test_callback_inspection_newsig(self):
- env = {}
- eval(compile('def foo(a, *, b=5): pass', '<foo>', 'exec'), env, env)
- route = bottle.Route(bottle.Bottle(), None, None, env['foo'])
- self.assertEqual(set(route.get_callback_args()), set(['a', 'b']))
+ def test_callback_inspection_newsig(self):
+ env = {}
+ eval(compile('def foo(a, *, b=5): pass', '<foo>', 'exec'), env, env)
+ route = bottle.Route(bottle.Bottle(), None, None, env['foo'])
+ self.assertEqual(set(route.get_callback_args()), set(['a', 'b']))
diff --git a/test/test_wsgi.py b/test/test_wsgi.py
index 6680f04..9f46fa7 100755
--- a/test/test_wsgi.py
+++ b/test/test_wsgi.py
@@ -104,8 +104,7 @@ class TestWsgi(ServerTestBase):
def test_utf8_header(self):
header = 'öäü'
- if bottle.py3k:
- header = header.encode('utf8').decode('latin1')
+ header = header.encode('utf8').decode('latin1')
@bottle.route('/test')
def test():
h = bottle.request.get_header('X-Test')
diff --git a/test/tools.py b/test/tools.py
index a66315c..8f15133 100755
--- a/test/tools.py
+++ b/test/tools.py
@@ -12,7 +12,7 @@ import wsgiref.validate
import mimetypes
import uuid
-from bottle import tob, tonat, BytesIO, py3k, unicode
+from bottle import tob, tonat, BytesIO, unicode
def warn(msg):
@@ -83,10 +83,8 @@ def api(introduced, deprecated=None, removed=None):
def wsgistr(s):
- if py3k:
- return s.encode('utf8').decode('latin1')
- else:
- return s
+ return s.encode('utf8').decode('latin1')
+
class ServerTestBase(unittest.TestCase):
def setUp(self):