remove _compat module

This commit is contained in:
David Lord 2020-04-03 18:33:40 -07:00
parent 1263d3bd14
commit 662c245795
No known key found for this signature in database
GPG key ID: 7A1C87E3F5BC42A8
20 changed files with 68 additions and 274 deletions

View file

@ -1,115 +0,0 @@
# -*- coding: utf-8 -*-
"""
flask._compat
~~~~~~~~~~~~~
Some py2/py3 compatibility support based on a stripped down
version of six so we don't have to depend on a specific version
of it.
:copyright: 2010 Pallets
:license: BSD-3-Clause
"""
import sys
PY2 = sys.version_info[0] == 2
_identity = lambda x: x
try: # Python 2
text_type = unicode
string_types = (str, unicode)
integer_types = (int, long)
except NameError: # Python 3
text_type = str
string_types = (str,)
integer_types = (int,)
if not PY2:
iterkeys = lambda d: iter(d.keys())
itervalues = lambda d: iter(d.values())
iteritems = lambda d: iter(d.items())
from inspect import getfullargspec as getargspec
from io import StringIO
import collections.abc as collections_abc
def reraise(tp, value, tb=None):
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
raise value
implements_to_string = _identity
else:
iterkeys = lambda d: d.iterkeys()
itervalues = lambda d: d.itervalues()
iteritems = lambda d: d.iteritems()
from inspect import getargspec
from cStringIO import StringIO
import collections as collections_abc
exec("def reraise(tp, value, tb=None):\n raise tp, value, tb")
def implements_to_string(cls):
cls.__unicode__ = cls.__str__
cls.__str__ = lambda x: x.__unicode__().encode("utf-8")
return cls
def with_metaclass(meta, *bases):
"""Create a base class with a metaclass."""
# This requires a bit of explanation: the basic idea is to make a
# dummy metaclass for one level of class instantiation that replaces
# itself with the actual metaclass.
class metaclass(type):
def __new__(metacls, name, this_bases, d):
return meta(name, bases, d)
return type.__new__(metaclass, "temporary_class", (), {})
# Certain versions of pypy have a bug where clearing the exception stack
# breaks the __exit__ function in a very peculiar way. The second level of
# exception blocks is necessary because pypy seems to forget to check if an
# exception happened until the next bytecode instruction?
#
# Relevant PyPy bugfix commit:
# https://bitbucket.org/pypy/pypy/commits/77ecf91c635a287e88e60d8ddb0f4e9df4003301
# According to ronan on #pypy IRC, it is released in PyPy2 2.3 and later
# versions.
#
# Ubuntu 14.04 has PyPy 2.2.1, which does exhibit this bug.
BROKEN_PYPY_CTXMGR_EXIT = False
if hasattr(sys, "pypy_version_info"):
class _Mgr(object):
def __enter__(self):
return self
def __exit__(self, *args):
if hasattr(sys, "exc_clear"):
# Python 3 (PyPy3) doesn't have exc_clear
sys.exc_clear()
try:
try:
with _Mgr():
raise AssertionError()
except: # noqa: B001
# We intentionally use a bare except here. See the comment above
# regarding a pypy bug as to why.
raise
except TypeError:
BROKEN_PYPY_CTXMGR_EXIT = True
except AssertionError:
pass
try:
from os import fspath
except ImportError:
# Backwards compatibility as proposed in PEP 0519:
# https://www.python.org/dev/peps/pep-0519/#backwards-compatibility
def fspath(path):
return path.__fspath__() if hasattr(path, "__fspath__") else path

View file

@ -31,10 +31,6 @@ from werkzeug.wrappers import BaseResponse
from . import cli from . import cli
from . import json from . import json
from ._compat import integer_types
from ._compat import reraise
from ._compat import string_types
from ._compat import text_type
from .config import Config from .config import Config
from .config import ConfigAttribute from .config import ConfigAttribute
from .ctx import _AppCtxGlobals from .ctx import _AppCtxGlobals
@ -1179,10 +1175,10 @@ class Flask(_PackageBoundObject):
# a tuple of only ``GET`` as default. # a tuple of only ``GET`` as default.
if methods is None: if methods is None:
methods = getattr(view_func, "methods", None) or ("GET",) methods = getattr(view_func, "methods", None) or ("GET",)
if isinstance(methods, string_types): if isinstance(methods, str):
raise TypeError( raise TypeError(
"Allowed methods have to be iterables of strings, " "Allowed methods must be a list of strings, for"
'for example: @app.route(..., methods=["POST"])' ' example: @app.route(..., methods=["POST"])'
) )
methods = set(item.upper() for item in methods) methods = set(item.upper() for item in methods)
@ -1278,7 +1274,7 @@ class Flask(_PackageBoundObject):
:param exc_class_or_code: Any exception class, or an HTTP status :param exc_class_or_code: Any exception class, or an HTTP status
code as an integer. code as an integer.
""" """
if isinstance(exc_class_or_code, integer_types): if isinstance(exc_class_or_code, int):
exc_class = default_exceptions[exc_class_or_code] exc_class = default_exceptions[exc_class_or_code]
else: else:
exc_class = exc_class_or_code exc_class = exc_class_or_code
@ -1727,13 +1723,6 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.7 .. versionadded:: 0.7
""" """
exc_type, exc_value, tb = sys.exc_info()
assert exc_value is e
# ensure not to trash sys.exc_info() at that point in case someone
# wants the traceback preserved in handle_http_exception. Of course
# we cannot prevent users from trashing it themselves in a custom
# trap_http_exception method so that's their fault then.
if isinstance(e, BadRequestKeyError): if isinstance(e, BadRequestKeyError):
if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]: if self.debug or self.config["TRAP_BAD_REQUEST_ERRORS"]:
e.show_exception = True e.show_exception = True
@ -1752,7 +1741,8 @@ class Flask(_PackageBoundObject):
handler = self._find_error_handler(e) handler = self._find_error_handler(e)
if handler is None: if handler is None:
reraise(exc_type, exc_value, tb) raise
return handler(e) return handler(e)
def handle_exception(self, e): def handle_exception(self, e):
@ -1789,20 +1779,18 @@ class Flask(_PackageBoundObject):
.. versionadded:: 0.3 .. versionadded:: 0.3
""" """
exc_type, exc_value, tb = sys.exc_info() exc_info = sys.exc_info()
got_request_exception.send(self, exception=e) got_request_exception.send(self, exception=e)
if self.propagate_exceptions: if self.propagate_exceptions:
# if we want to repropagate the exception, we can attempt to # Re-raise if called with an active exception, otherwise
# raise it with the whole traceback in case we can do that # raise the passed in exception.
# (the function was actually called from the except part) if exc_info[1] is e:
# otherwise, we just raise the error again raise
if exc_value is e:
reraise(exc_type, exc_value, tb)
else:
raise e
self.log_exception((exc_type, exc_value, tb)) raise e
self.log_exception(exc_info)
server_error = InternalServerError() server_error = InternalServerError()
# TODO: pass as param when Werkzeug>=1.0.0 is required # TODO: pass as param when Werkzeug>=1.0.0 is required
# TODO: also remove note about this from docstring and docs # TODO: also remove note about this from docstring and docs
@ -2026,7 +2014,7 @@ class Flask(_PackageBoundObject):
# make sure the body is an instance of the response class # make sure the body is an instance of the response class
if not isinstance(rv, self.response_class): if not isinstance(rv, self.response_class):
if isinstance(rv, (text_type, bytes, bytearray)): if isinstance(rv, (str, bytes, bytearray)):
# let the response class set the status and headers instead of # let the response class set the status and headers instead of
# waiting to do it manually, so that the class can handle any # waiting to do it manually, so that the class can handle any
# special logic # special logic
@ -2040,13 +2028,12 @@ class Flask(_PackageBoundObject):
try: try:
rv = self.response_class.force_type(rv, request.environ) rv = self.response_class.force_type(rv, request.environ)
except TypeError as e: except TypeError as e:
new_error = TypeError( raise TypeError(
"{e}\nThe view function did not return a valid" "{e}\nThe view function did not return a valid"
" response. The return type must be a string, dict, tuple," " response. The return type must be a string, dict, tuple,"
" Response instance, or WSGI callable, but it was a" " Response instance, or WSGI callable, but it was a"
" {rv.__class__.__name__}.".format(e=e, rv=rv) " {rv.__class__.__name__}.".format(e=e, rv=rv)
) ).with_traceback(sys.exc_info()[2])
reraise(TypeError, new_error, sys.exc_info()[2])
else: else:
raise TypeError( raise TypeError(
"The view function did not return a valid" "The view function did not return a valid"
@ -2057,7 +2044,7 @@ class Flask(_PackageBoundObject):
# prefer the status if it was provided # prefer the status if it was provided
if status is not None: if status is not None:
if isinstance(status, (text_type, bytes, bytearray)): if isinstance(status, (str, bytes, bytearray)):
rv.status = status rv.status = status
else: else:
rv.status_code = status rv.status_code = status
@ -2121,23 +2108,24 @@ class Flask(_PackageBoundObject):
func(endpoint, values) func(endpoint, values)
def handle_url_build_error(self, error, endpoint, values): def handle_url_build_error(self, error, endpoint, values):
"""Handle :class:`~werkzeug.routing.BuildError` on :meth:`url_for`. """Handle :class:`~werkzeug.routing.BuildError` on
:meth:`url_for`.
""" """
exc_type, exc_value, tb = sys.exc_info()
for handler in self.url_build_error_handlers: for handler in self.url_build_error_handlers:
try: try:
rv = handler(error, endpoint, values) rv = handler(error, endpoint, values)
except BuildError as e:
# make error available outside except block
error = e
else:
if rv is not None: if rv is not None:
return rv return rv
except BuildError as e:
# make error available outside except block (py3)
error = e
# At this point we want to reraise the exception. If the error is # Re-raise if called with an active exception, otherwise raise
# still the same one we can reraise it with the original traceback, # the passed in exception.
# otherwise we raise it from here. if error is sys.exc_info()[1]:
if error is exc_value: raise
reraise(exc_type, exc_value, tb)
raise error raise error
def preprocess_request(self): def preprocess_request(self):

View file

@ -25,10 +25,6 @@ from threading import Thread
import click import click
from werkzeug.utils import import_string from werkzeug.utils import import_string
from ._compat import getargspec
from ._compat import itervalues
from ._compat import reraise
from ._compat import text_type
from .globals import current_app from .globals import current_app
from .helpers import get_debug_flag from .helpers import get_debug_flag
from .helpers import get_env from .helpers import get_env
@ -63,7 +59,7 @@ def find_best_app(script_info, module):
return app return app
# Otherwise find the only object that is a Flask instance. # Otherwise find the only object that is a Flask instance.
matches = [v for v in itervalues(module.__dict__) if isinstance(v, Flask)] matches = [v for v in module.__dict__.values() if isinstance(v, Flask)]
if len(matches) == 1: if len(matches) == 1:
return matches[0] return matches[0]
@ -105,7 +101,7 @@ def call_factory(script_info, app_factory, arguments=()):
of arguments. Checks for the existence of a script_info argument and calls of arguments. Checks for the existence of a script_info argument and calls
the app_factory depending on that and the arguments provided. the app_factory depending on that and the arguments provided.
""" """
args_spec = getargspec(app_factory) args_spec = inspect.getfullargspec(app_factory)
arg_names = args_spec.args arg_names = args_spec.args
arg_defaults = args_spec.defaults arg_defaults = args_spec.defaults
@ -241,7 +237,7 @@ def locate_app(script_info, module_name, app_name, raise_if_not_found=True):
except ImportError: except ImportError:
# Reraise the ImportError if it occurred within the imported module. # Reraise the ImportError if it occurred within the imported module.
# Determine this by checking whether the trace has a depth > 1. # Determine this by checking whether the trace has a depth > 1.
if sys.exc_info()[-1].tb_next: if sys.exc_info()[2].tb_next:
raise NoAppException( raise NoAppException(
'While importing "{name}", an ImportError was raised:' 'While importing "{name}", an ImportError was raised:'
"\n\n{tb}".format(name=module_name, tb=traceback.format_exc()) "\n\n{tb}".format(name=module_name, tb=traceback.format_exc())
@ -327,7 +323,7 @@ class DispatchingApp(object):
exc_info = self._bg_loading_exc_info exc_info = self._bg_loading_exc_info
if exc_info is not None: if exc_info is not None:
self._bg_loading_exc_info = None self._bg_loading_exc_info = None
reraise(*exc_info) raise exc_info
def _load_unlocked(self): def _load_unlocked(self):
__traceback_hide__ = True # noqa: F841 __traceback_hide__ = True # noqa: F841
@ -741,11 +737,7 @@ def _validate_key(ctx, param, value):
""" """
cert = ctx.params.get("cert") cert = ctx.params.get("cert")
is_adhoc = cert == "adhoc" is_adhoc = cert == "adhoc"
is_context = ssl and isinstance(cert, ssl.SSLContext)
if sys.version_info < (2, 7, 9):
is_context = cert and not isinstance(cert, (text_type, bytes))
else:
is_context = ssl and isinstance(cert, ssl.SSLContext)
if value is not None: if value is not None:
if is_adhoc: if is_adhoc:

View file

@ -14,9 +14,6 @@ import types
from werkzeug.utils import import_string from werkzeug.utils import import_string
from ._compat import iteritems
from ._compat import string_types
class ConfigAttribute(object): class ConfigAttribute(object):
"""Makes an attribute forward to the config""" """Makes an attribute forward to the config"""
@ -169,7 +166,7 @@ class Config(dict):
:param obj: an import name or object :param obj: an import name or object
""" """
if isinstance(obj, string_types): if isinstance(obj, str):
obj = import_string(obj) obj = import_string(obj)
for key in dir(obj): for key in dir(obj):
if key.isupper(): if key.isupper():
@ -261,7 +258,7 @@ class Config(dict):
.. versionadded:: 0.11 .. versionadded:: 0.11
""" """
rv = {} rv = {}
for k, v in iteritems(self): for k, v in self.items():
if not k.startswith(namespace): if not k.startswith(namespace):
continue continue
if trim_namespace: if trim_namespace:

View file

@ -13,8 +13,6 @@ from functools import update_wrapper
from werkzeug.exceptions import HTTPException from werkzeug.exceptions import HTTPException
from ._compat import BROKEN_PYPY_CTXMGR_EXIT
from ._compat import reraise
from .globals import _app_ctx_stack from .globals import _app_ctx_stack
from .globals import _request_ctx_stack from .globals import _request_ctx_stack
from .signals import appcontext_popped from .signals import appcontext_popped
@ -248,9 +246,6 @@ class AppContext(object):
def __exit__(self, exc_type, exc_value, tb): def __exit__(self, exc_type, exc_value, tb):
self.pop(exc_value) self.pop(exc_value)
if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
reraise(exc_type, exc_value, tb)
class RequestContext(object): class RequestContext(object):
"""The request context contains all request relevant information. It is """The request context contains all request relevant information. It is
@ -463,9 +458,6 @@ class RequestContext(object):
# See flask.testing for how this works. # See flask.testing for how this works.
self.auto_pop(exc_value) self.auto_pop(exc_value)
if BROKEN_PYPY_CTXMGR_EXIT and exc_type is not None:
reraise(exc_type, exc_value, tb)
def __repr__(self): def __repr__(self):
return "<%s '%s' [%s] of %s>" % ( return "<%s '%s' [%s] of %s>" % (
self.__class__.__name__, self.__class__.__name__,

View file

@ -11,8 +11,6 @@
import os import os
from warnings import warn from warnings import warn
from ._compat import implements_to_string
from ._compat import text_type
from .app import Flask from .app import Flask
from .blueprints import Blueprint from .blueprints import Blueprint
from .globals import _request_ctx_stack from .globals import _request_ctx_stack
@ -24,7 +22,6 @@ class UnexpectedUnicodeError(AssertionError, UnicodeError):
""" """
@implements_to_string
class DebugFilesKeyError(KeyError, AssertionError): class DebugFilesKeyError(KeyError, AssertionError):
"""Raised from request.files during debugging. The idea is that it can """Raised from request.files during debugging. The idea is that it can
provide a better error message than just a generic KeyError/BadRequest. provide a better error message than just a generic KeyError/BadRequest.
@ -110,13 +107,13 @@ def _dump_loader_info(loader):
if key.startswith("_"): if key.startswith("_"):
continue continue
if isinstance(value, (tuple, list)): if isinstance(value, (tuple, list)):
if not all(isinstance(x, (str, text_type)) for x in value): if not all(isinstance(x, str) for x in value):
continue continue
yield "%s:" % key yield "%s:" % key
for item in value: for item in value:
yield " - %s" % item yield " - %s" % item
continue continue
elif not isinstance(value, (str, text_type, int, float, bool)): elif not isinstance(value, (str, int, float, bool)):
continue continue
yield "%s: %r" % (key, value) yield "%s: %r" % (key, value)

View file

@ -30,10 +30,6 @@ from werkzeug.routing import BuildError
from werkzeug.urls import url_quote from werkzeug.urls import url_quote
from werkzeug.wsgi import wrap_file from werkzeug.wsgi import wrap_file
from ._compat import fspath
from ._compat import PY2
from ._compat import string_types
from ._compat import text_type
from .globals import _app_ctx_stack from .globals import _app_ctx_stack
from .globals import _request_ctx_stack from .globals import _request_ctx_stack
from .globals import current_app from .globals import current_app
@ -576,9 +572,9 @@ def send_file(
fsize = None fsize = None
if hasattr(filename_or_fp, "__fspath__"): if hasattr(filename_or_fp, "__fspath__"):
filename_or_fp = fspath(filename_or_fp) filename_or_fp = os.fspath(filename_or_fp)
if isinstance(filename_or_fp, string_types): if isinstance(filename_or_fp, str):
filename = filename_or_fp filename = filename_or_fp
if not os.path.isabs(filename): if not os.path.isabs(filename):
filename = os.path.join(current_app.root_path, filename) filename = os.path.join(current_app.root_path, filename)
@ -608,7 +604,7 @@ def send_file(
if attachment_filename is None: if attachment_filename is None:
raise TypeError("filename unavailable, required for sending as attachment") raise TypeError("filename unavailable, required for sending as attachment")
if not isinstance(attachment_filename, text_type): if not isinstance(attachment_filename, str):
attachment_filename = attachment_filename.decode("utf-8") attachment_filename = attachment_filename.decode("utf-8")
try: try:
@ -618,7 +614,7 @@ def send_file(
"filename": unicodedata.normalize("NFKD", attachment_filename).encode( "filename": unicodedata.normalize("NFKD", attachment_filename).encode(
"ascii", "ignore" "ascii", "ignore"
), ),
"filename*": "UTF-8''%s" % url_quote(attachment_filename, safe=b""), "filename*": "UTF-8''%s" % url_quote(attachment_filename, safe=""),
} }
else: else:
filenames = {"filename": attachment_filename} filenames = {"filename": attachment_filename}
@ -678,7 +674,7 @@ def send_file(
os.path.getsize(filename), os.path.getsize(filename),
adler32( adler32(
filename.encode("utf-8") filename.encode("utf-8")
if isinstance(filename, text_type) if isinstance(filename, str)
else filename else filename
) )
& 0xFFFFFFFF, & 0xFFFFFFFF,
@ -769,8 +765,8 @@ def send_from_directory(directory, filename, **options):
:param options: optional keyword arguments that are directly :param options: optional keyword arguments that are directly
forwarded to :func:`send_file`. forwarded to :func:`send_file`.
""" """
filename = fspath(filename) filename = os.fspath(filename)
directory = fspath(directory) directory = os.fspath(directory)
filename = safe_join(directory, filename) filename = safe_join(directory, filename)
if not os.path.isabs(filename): if not os.path.isabs(filename):
filename = os.path.join(current_app.root_path, filename) filename = os.path.join(current_app.root_path, filename)
@ -1140,22 +1136,12 @@ def total_seconds(td):
def is_ip(value): def is_ip(value):
"""Determine if the given string is an IP address. """Determine if the given string is an IP address.
Python 2 on Windows doesn't provide ``inet_pton``, so this only
checks IPv4 addresses in that environment.
:param value: value to check :param value: value to check
:type value: str :type value: str
:return: True if string is an IP address :return: True if string is an IP address
:rtype: bool :rtype: bool
""" """
if PY2 and os.name == "nt":
try:
socket.inet_aton(value)
return True
except socket.error:
return False
for family in (socket.AF_INET, socket.AF_INET6): for family in (socket.AF_INET, socket.AF_INET6):
try: try:
socket.inet_pton(family, value) socket.inet_pton(family, value)

View file

@ -16,14 +16,13 @@ from itsdangerous import json as _json
from jinja2 import Markup from jinja2 import Markup
from werkzeug.http import http_date from werkzeug.http import http_date
from .._compat import PY2
from .._compat import text_type
from ..globals import current_app from ..globals import current_app
from ..globals import request from ..globals import request
try: try:
import dataclasses import dataclasses
except ImportError: except ImportError:
# Python < 3.7
dataclasses = None dataclasses = None
# Figure out if simplejson escapes slashes. This behavior was changed # Figure out if simplejson escapes slashes. This behavior was changed
@ -96,7 +95,7 @@ class JSONEncoder(_json.JSONEncoder):
if dataclasses and dataclasses.is_dataclass(o): if dataclasses and dataclasses.is_dataclass(o):
return dataclasses.asdict(o) return dataclasses.asdict(o)
if hasattr(o, "__html__"): if hasattr(o, "__html__"):
return text_type(o.__html__()) return str(o.__html__())
return _json.JSONEncoder.default(self, o) return _json.JSONEncoder.default(self, o)
@ -209,7 +208,7 @@ def dumps(obj, app=None, **kwargs):
_dump_arg_defaults(kwargs, app=app) _dump_arg_defaults(kwargs, app=app)
encoding = kwargs.pop("encoding", None) encoding = kwargs.pop("encoding", None)
rv = _json.dumps(obj, **kwargs) rv = _json.dumps(obj, **kwargs)
if encoding is not None and isinstance(rv, text_type): if encoding is not None and isinstance(rv, str):
rv = rv.encode(encoding) rv = rv.encode(encoding)
return rv return rv
@ -256,8 +255,7 @@ def loads(s, app=None, **kwargs):
def load(fp, app=None, **kwargs): def load(fp, app=None, **kwargs):
"""Like :func:`loads` but reads from a file object.""" """Like :func:`loads` but reads from a file object."""
_load_arg_defaults(kwargs, app=app) _load_arg_defaults(kwargs, app=app)
if not PY2: fp = _wrap_reader_for_text(fp, kwargs.pop("encoding", None) or "utf-8")
fp = _wrap_reader_for_text(fp, kwargs.pop("encoding", None) or "utf-8")
return _json.load(fp, **kwargs) return _json.load(fp, **kwargs)
@ -300,7 +298,7 @@ def htmlsafe_dumps(obj, **kwargs):
def htmlsafe_dump(obj, fp, **kwargs): def htmlsafe_dump(obj, fp, **kwargs):
"""Like :func:`htmlsafe_dumps` but writes into a file object.""" """Like :func:`htmlsafe_dumps` but writes into a file object."""
fp.write(text_type(htmlsafe_dumps(obj, **kwargs))) fp.write(str(htmlsafe_dumps(obj, **kwargs)))
def jsonify(*args, **kwargs): def jsonify(*args, **kwargs):

View file

@ -50,8 +50,6 @@ from jinja2 import Markup
from werkzeug.http import http_date from werkzeug.http import http_date
from werkzeug.http import parse_date from werkzeug.http import parse_date
from .._compat import iteritems
from .._compat import text_type
from ..json import dumps from ..json import dumps
from ..json import loads from ..json import loads
@ -124,7 +122,7 @@ class PassDict(JSONTag):
def to_json(self, value): def to_json(self, value):
# JSON objects may only have string keys, so don't bother tagging the # JSON objects may only have string keys, so don't bother tagging the
# key here. # key here.
return dict((k, self.serializer.tag(v)) for k, v in iteritems(value)) return dict((k, self.serializer.tag(v)) for k, v in value.items())
tag = to_json tag = to_json
@ -181,7 +179,7 @@ class TagMarkup(JSONTag):
return callable(getattr(value, "__html__", None)) return callable(getattr(value, "__html__", None))
def to_json(self, value): def to_json(self, value):
return text_type(value.__html__()) return str(value.__html__())
def to_python(self, value): def to_python(self, value):
return Markup(value) return Markup(value)

View file

@ -10,19 +10,19 @@
""" """
import hashlib import hashlib
import warnings import warnings
from collections.abc import MutableMapping
from datetime import datetime from datetime import datetime
from itsdangerous import BadSignature from itsdangerous import BadSignature
from itsdangerous import URLSafeTimedSerializer from itsdangerous import URLSafeTimedSerializer
from werkzeug.datastructures import CallbackDict from werkzeug.datastructures import CallbackDict
from ._compat import collections_abc
from .helpers import is_ip from .helpers import is_ip
from .helpers import total_seconds from .helpers import total_seconds
from .json.tag import TaggedJSONSerializer from .json.tag import TaggedJSONSerializer
class SessionMixin(collections_abc.MutableMapping): class SessionMixin(MutableMapping):
"""Expands a basic dictionary with session attributes.""" """Expands a basic dictionary with session attributes."""
@property @property

View file

@ -8,7 +8,6 @@
:copyright: 2010 Pallets :copyright: 2010 Pallets
:license: BSD-3-Clause :license: BSD-3-Clause
""" """
from ._compat import with_metaclass
from .globals import request from .globals import request
@ -135,7 +134,7 @@ class MethodViewType(type):
cls.methods = methods cls.methods = methods
class MethodView(with_metaclass(MethodViewType, View)): class MethodView(View, metaclass=MethodViewType):
"""A class-based view that dispatches request methods to the corresponding """A class-based view that dispatches request methods to the corresponding
class methods. For example, if you implement a ``get`` method, it will be class methods. For example, if you implement a ``get`` method, it will be
used to handle ``GET`` requests. :: used to handle ``GET`` requests. ::

View file

@ -24,7 +24,6 @@ from werkzeug.http import parse_date
from werkzeug.routing import BuildError from werkzeug.routing import BuildError
import flask import flask
from flask._compat import text_type
def test_options_work(app, client): def test_options_work(app, client):
@ -413,7 +412,7 @@ def test_session_expiration(app, client):
@app.route("/test") @app.route("/test")
def test(): def test():
return text_type(flask.session.permanent) return str(flask.session.permanent)
rv = client.get("/") rv = client.get("/")
assert "set-cookie" in rv.headers assert "set-cookie" in rv.headers

View file

@ -15,7 +15,6 @@ from jinja2 import TemplateNotFound
from werkzeug.http import parse_cache_control_header from werkzeug.http import parse_cache_control_header
import flask import flask
from flask._compat import text_type
def test_blueprint_specific_error_handling(app, client): def test_blueprint_specific_error_handling(app, client):
@ -150,7 +149,7 @@ def test_blueprint_url_defaults(app, client):
@bp.route("/bar") @bp.route("/bar")
def bar(bar): def bar(bar):
return text_type(bar) return str(bar)
app.register_blueprint(bp, url_prefix="/1", url_defaults={"bar": 23}) app.register_blueprint(bp, url_prefix="/1", url_defaults={"bar": 23})
app.register_blueprint(bp, url_prefix="/2", url_defaults={"bar": 19}) app.register_blueprint(bp, url_prefix="/2", url_defaults={"bar": 19})

View file

@ -14,7 +14,6 @@ from datetime import timedelta
import pytest import pytest
import flask import flask
from flask._compat import PY2
# config keys used for the TestConfig # config keys used for the TestConfig
@ -198,6 +197,4 @@ def test_from_pyfile_weird_encoding(tmpdir, encoding):
app = flask.Flask(__name__) app = flask.Flask(__name__)
app.config.from_pyfile(str(f)) app.config.from_pyfile(str(f))
value = app.config["TEST_VALUE"] value = app.config["TEST_VALUE"]
if PY2:
value = value.decode(encoding)
assert value == u"föö" assert value == u"föö"

View file

@ -24,9 +24,6 @@ from werkzeug.http import parse_options_header
import flask import flask
from flask import json from flask import json
from flask._compat import PY2
from flask._compat import StringIO
from flask._compat import text_type
from flask.helpers import get_debug_flag from flask.helpers import get_debug_flag
from flask.helpers import get_env from flask.helpers import get_env
@ -116,7 +113,7 @@ class TestJSON(object):
def test_json_bad_requests(self, app, client): def test_json_bad_requests(self, app, client):
@app.route("/json", methods=["POST"]) @app.route("/json", methods=["POST"])
def return_json(): def return_json():
return flask.jsonify(foo=text_type(flask.request.get_json())) return flask.jsonify(foo=str(flask.request.get_json()))
rv = client.post("/json", data="malformed", content_type="application/json") rv = client.post("/json", data="malformed", content_type="application/json")
assert rv.status_code == 400 assert rv.status_code == 400
@ -140,7 +137,7 @@ class TestJSON(object):
def test_json_dump_to_file(self, app, app_ctx): def test_json_dump_to_file(self, app, app_ctx):
test_data = {"name": "Flask"} test_data = {"name": "Flask"}
out = StringIO() out = io.StringIO()
flask.json.dump(test_data, out) flask.json.dump(test_data, out)
out.seek(0) out.seek(0)
@ -254,7 +251,7 @@ class TestJSON(object):
@app.route("/add", methods=["POST"]) @app.route("/add", methods=["POST"])
def add(): def add():
json = flask.request.get_json() json = flask.request.get_json()
return text_type(json["a"] + json["b"]) return str(json["a"] + json["b"])
rv = client.post( rv = client.post(
"/add", "/add",
@ -267,7 +264,7 @@ class TestJSON(object):
render = flask.render_template_string render = flask.render_template_string
rv = flask.json.htmlsafe_dumps("</script>") rv = flask.json.htmlsafe_dumps("</script>")
assert rv == u'"\\u003c/script\\u003e"' assert rv == u'"\\u003c/script\\u003e"'
assert type(rv) == text_type assert type(rv) is str
rv = render('{{ "</script>"|tojson }}') rv = render('{{ "</script>"|tojson }}')
assert rv == '"\\u003c/script\\u003e"' assert rv == '"\\u003c/script\\u003e"'
rv = render('{{ "<\0/script>"|tojson }}') rv = render('{{ "<\0/script>"|tojson }}')
@ -447,7 +444,7 @@ class TestJSON(object):
assert lines == sorted_by_str assert lines == sorted_by_str
class PyStringIO(object): class PyBytesIO(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
self._io = io.BytesIO(*args, **kwargs) self._io = io.BytesIO(*args, **kwargs)
@ -503,11 +500,7 @@ class TestSendfile(object):
[ [
lambda app: open(os.path.join(app.static_folder, "index.html"), "rb"), lambda app: open(os.path.join(app.static_folder, "index.html"), "rb"),
lambda app: io.BytesIO(b"Test"), lambda app: io.BytesIO(b"Test"),
pytest.param( lambda app: PyBytesIO(b"Test"),
lambda app: StringIO("Test"),
marks=pytest.mark.skipif(not PY2, reason="Python 2 only"),
),
lambda app: PyStringIO(b"Test"),
], ],
) )
@pytest.mark.usefixtures("req_ctx") @pytest.mark.usefixtures("req_ctx")
@ -525,10 +518,7 @@ class TestSendfile(object):
"opener", "opener",
[ [
lambda app: io.StringIO(u"Test"), lambda app: io.StringIO(u"Test"),
pytest.param( lambda app: open(os.path.join(app.static_folder, "index.html")),
lambda app: open(os.path.join(app.static_folder, "index.html")),
marks=pytest.mark.skipif(PY2, reason="Python 3 only"),
),
], ],
) )
@pytest.mark.usefixtures("req_ctx") @pytest.mark.usefixtures("req_ctx")

View file

@ -12,7 +12,6 @@ import sys
import pytest import pytest
import flask import flask
from flask._compat import PY2
def test_explicit_instance_paths(modules_tmpdir): def test_explicit_instance_paths(modules_tmpdir):
@ -128,19 +127,3 @@ def test_egg_installed_paths(install_egg, modules_tmpdir, modules_tmpdir_prefix)
finally: finally:
if "site_egg" in sys.modules: if "site_egg" in sys.modules:
del sys.modules["site_egg"] del sys.modules["site_egg"]
@pytest.mark.skipif(not PY2, reason="This only works under Python 2.")
def test_meta_path_loader_without_is_package(request, modules_tmpdir):
app = modules_tmpdir.join("unimportable.py")
app.write("import flask\napp = flask.Flask(__name__)")
class Loader(object):
def find_module(self, name, path=None):
return self
sys.meta_path.append(Loader())
request.addfinalizer(sys.meta_path.pop)
with pytest.raises(AttributeError):
import unimportable # noqa: F401

View file

@ -8,10 +8,10 @@ tests.test_logging
""" """
import logging import logging
import sys import sys
from io import StringIO
import pytest import pytest
from flask._compat import StringIO
from flask.logging import default_handler from flask.logging import default_handler
from flask.logging import has_level_handler from flask.logging import has_level_handler
from flask.logging import wsgi_errors_stream from flask.logging import wsgi_errors_stream

View file

@ -1,6 +0,0 @@
import io
def test_changelog_utf8_compatible():
with io.open("CHANGES.rst", encoding="UTF-8") as f:
f.read()

View file

@ -9,8 +9,9 @@
:copyright: 2010 Pallets :copyright: 2010 Pallets
:license: BSD-3-Clause :license: BSD-3-Clause
""" """
from io import StringIO
import flask import flask
from flask._compat import StringIO
def test_suppressed_exception_logging(): def test_suppressed_exception_logging():

View file

@ -14,7 +14,6 @@ import werkzeug
import flask import flask
from flask import appcontext_popped from flask import appcontext_popped
from flask._compat import text_type
from flask.cli import ScriptInfo from flask.cli import ScriptInfo
from flask.json import jsonify from flask.json import jsonify
from flask.testing import EnvironBuilder from flask.testing import EnvironBuilder
@ -184,7 +183,7 @@ def test_redirect_keep_session(app, client, app_ctx):
def test_session_transactions(app, client): def test_session_transactions(app, client):
@app.route("/") @app.route("/")
def index(): def index():
return text_type(flask.session["foo"]) return str(flask.session["foo"])
with client: with client:
with client.session_transaction() as sess: with client.session_transaction() as sess: