diff options
author | Marcel Hellkamp <marc@gsites.de> | 2020-01-01 16:28:31 +0100 |
---|---|---|
committer | Marcel Hellkamp <marc@gsites.de> | 2020-01-01 16:28:31 +0100 |
commit | 45692af31e6acdcb4332fefb2c8313965a2ff574 (patch) | |
tree | c97dffe7816971a1294053812cbbbbc1728939d4 | |
parent | ef156dbb3f040065bf021600c40cad34eb8b2046 (diff) | |
download | bottle-45692af31e6acdcb4332fefb2c8313965a2ff574.tar.gz |
Removed bottle.py3k flag and all python 2 only code.
-rwxr-xr-x | bottle.py | 148 | ||||
-rwxr-xr-x | test/test_environ.py | 22 | ||||
-rw-r--r-- | test/test_route.py | 11 | ||||
-rwxr-xr-x | test/test_wsgi.py | 3 | ||||
-rwxr-xr-x | test/tools.py | 8 |
5 files changed, 65 insertions, 127 deletions
@@ -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): |