From abc1505196ba3bc9517ec142ced7c1204c3ac21b Mon Sep 17 00:00:00 2001 From: Armin Ronacher Date: Thu, 30 May 2013 15:07:18 +0100 Subject: [PATCH] Fixed various issues on the Python 3 port --- flask/_compat.py | 4 ---- flask/json.py | 34 ++++++++++++++++++++++++++++++---- flask/testing.py | 8 ++++++-- 3 files changed, 36 insertions(+), 10 deletions(-) diff --git a/flask/_compat.py b/flask/_compat.py index 7c960ac6..edc9957a 100644 --- a/flask/_compat.py +++ b/flask/_compat.py @@ -47,8 +47,6 @@ if not PY2: encode_filename = _identity get_next = lambda x: x.__next__ - from urllib.parse import urlparse - else: unichr = unichr text_type = unicode @@ -86,8 +84,6 @@ else: return filename.encode('utf-8') return filename - from urlparse import urlparse - def with_metaclass(meta, *bases): # This requires a bit of explanation: the basic idea is to make a diff --git a/flask/json.py b/flask/json.py index 22f6067d..9e56073c 100644 --- a/flask/json.py +++ b/flask/json.py @@ -8,10 +8,11 @@ :copyright: (c) 2012 by Armin Ronacher. :license: BSD, see LICENSE for more details. """ +import io import uuid from datetime import datetime from .globals import current_app, request -from ._compat import text_type +from ._compat import text_type, PY2 from werkzeug.http import http_date @@ -33,6 +34,20 @@ __all__ = ['dump', 'dumps', 'load', 'loads', 'htmlsafe_dump', 'jsonify'] +def _wrap_reader_for_text(fp, encoding): + if isinstance(fp.read(0), bytes): + fp = io.TextIOWrapper(io.BufferedReader(fp), encoding) + return fp + + +def _wrap_writer_for_text(fp, encoding): + try: + fp.write('') + except TypeError: + fp = io.TextIOWrapper(fp, encoding) + return fp + + class JSONEncoder(_json.JSONEncoder): """The default Flask JSON encoder. This one extends the default simplejson encoder by also supporting ``datetime`` objects, ``UUID`` as well as @@ -100,13 +115,20 @@ def dumps(obj, **kwargs): and can be overriden by the simplejson ``ensure_ascii`` parameter. """ _dump_arg_defaults(kwargs) - return _json.dumps(obj, **kwargs) + encoding = kwargs.pop('encoding', None) + rv = _json.dumps(obj, **kwargs) + if encoding is not None and isinstance(rv, text_type): + rv = rv.encode(encoding) + return rv def dump(obj, fp, **kwargs): """Like :func:`dumps` but writes into a file object.""" _dump_arg_defaults(kwargs) - return _json.dump(obj, fp, **kwargs) + encoding = kwargs.pop('encoding', None) + if encoding is not None: + fp = _wrap_writer_for_text(fp, encoding) + _json.dump(obj, fp, **kwargs) def loads(s, **kwargs): @@ -115,6 +137,8 @@ def loads(s, **kwargs): application on the stack. """ _load_arg_defaults(kwargs) + if isinstance(s, bytes): + s = s.decode(kwargs.pop('encoding', None) or 'utf-8') return _json.loads(s, **kwargs) @@ -122,6 +146,8 @@ def load(fp, **kwargs): """Like :func:`loads` but reads from a file object. """ _load_arg_defaults(kwargs) + if not PY2: + fp = _wrap_reader_for_text(fp, kwargs.pop('encoding', None) or 'utf-8') return _json.load(fp, **kwargs) @@ -148,7 +174,7 @@ def jsonify(*args, **kwargs): to this function are the same as to the :class:`dict` constructor. Example usage:: - + from flask import jsonify @app.route('/_get_current_user') diff --git a/flask/testing.py b/flask/testing.py index 4c1f4550..1dc383af 100644 --- a/flask/testing.py +++ b/flask/testing.py @@ -13,7 +13,11 @@ from contextlib import contextmanager from werkzeug.test import Client, EnvironBuilder from flask import _request_ctx_stack -from ._compat import urlparse + +try: + from werkzeug.urls import url_parse +except ImportError: + from urlparse import urlsplit as url_parse def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs): @@ -21,7 +25,7 @@ def make_test_environ_builder(app, path='/', base_url=None, *args, **kwargs): http_host = app.config.get('SERVER_NAME') app_root = app.config.get('APPLICATION_ROOT') if base_url is None: - url = urlparse(path) + url = url_parse(path) base_url = 'http://%s/' % (url.netloc or http_host or 'localhost') if app_root: base_url += app_root.lstrip('/')