diff --git a/src/flask/cli.py b/src/flask/cli.py index 4b3da207..90abb0ce 100644 --- a/src/flask/cli.py +++ b/src/flask/cli.py @@ -721,12 +721,8 @@ class CertParamType(click.ParamType): obj = import_string(value, silent=True) - if sys.version_info < (2, 7, 9): - if obj: - return obj - else: - if isinstance(obj, ssl.SSLContext): - return obj + if isinstance(obj, ssl.SSLContext): + return obj raise diff --git a/src/flask/ctx.py b/src/flask/ctx.py index 040c4789..fbc1d3dc 100644 --- a/src/flask/ctx.py +++ b/src/flask/ctx.py @@ -221,8 +221,6 @@ class AppContext(object): def push(self): """Binds the app context to the current context.""" self._refcnt += 1 - if hasattr(sys, "exc_clear"): - sys.exc_clear() _app_ctx_stack.push(self) appcontext_pushed.send(self.app) @@ -371,9 +369,6 @@ class RequestContext(object): else: self._implicit_app_ctx_stack.append(None) - if hasattr(sys, "exc_clear"): - sys.exc_clear() - _request_ctx_stack.push(self) # Open the session at the moment that the request context is available. @@ -399,9 +394,9 @@ class RequestContext(object): Added the `exc` argument. """ app_ctx = self._implicit_app_ctx_stack.pop() + clear_request = False try: - clear_request = False if not self._implicit_app_ctx_stack: self.preserved = False self._preserved_exc = None @@ -409,13 +404,6 @@ class RequestContext(object): exc = sys.exc_info()[1] self.app.do_teardown_request(exc) - # If this interpreter supports clearing the exception information - # we do that now. This will only go into effect on Python 2.x, - # on 3.x it disappears automatically at the end of the exception - # stack. - if hasattr(sys, "exc_clear"): - sys.exc_clear() - request_close = getattr(self.request, "close", None) if request_close is not None: request_close() diff --git a/src/flask/helpers.py b/src/flask/helpers.py index 6bfc162d..9e3bd6b5 100644 --- a/src/flask/helpers.py +++ b/src/flask/helpers.py @@ -634,11 +634,7 @@ def send_file( mtime = os.path.getmtime(filename) fsize = os.path.getsize(filename) elif isinstance(file, io.BytesIO): - try: - fsize = file.getbuffer().nbytes - except AttributeError: - # Python 2 doesn't have getbuffer - fsize = len(file.getvalue()) + fsize = file.getbuffer().nbytes elif isinstance(file, io.TextIOBase): raise ValueError("Files must be opened in binary mode or use BytesIO.") @@ -799,8 +795,6 @@ def get_root_path(import_name): if loader is None or import_name == "__main__": return os.getcwd() - # For .egg, zipimporter does not have get_filename until Python 2.7. - # Some other loaders might exhibit the same behavior. if hasattr(loader, "get_filename"): filepath = loader.get_filename(import_name) else: @@ -857,30 +851,29 @@ def _matching_loader_thinks_module_is_package(loader, mod_name): def _find_package_path(root_mod_name): """Find the path where the module's root exists in""" - if sys.version_info >= (3, 4): - import importlib.util + import importlib.util - try: - spec = importlib.util.find_spec(root_mod_name) - if spec is None: - raise ValueError("not found") - # ImportError: the machinery told us it does not exist - # ValueError: - # - the module name was invalid - # - the module name is __main__ - # - *we* raised `ValueError` due to `spec` being `None` - except (ImportError, ValueError): - pass # handled below + try: + spec = importlib.util.find_spec(root_mod_name) + if spec is None: + raise ValueError("not found") + # ImportError: the machinery told us it does not exist + # ValueError: + # - the module name was invalid + # - the module name is __main__ + # - *we* raised `ValueError` due to `spec` being `None` + except (ImportError, ValueError): + pass # handled below + else: + # namespace package + if spec.origin in {"namespace", None}: + return os.path.dirname(next(iter(spec.submodule_search_locations))) + # a package (with __init__.py) + elif spec.submodule_search_locations: + return os.path.dirname(os.path.dirname(spec.origin)) + # just a normal module else: - # namespace package - if spec.origin in {"namespace", None}: - return os.path.dirname(next(iter(spec.submodule_search_locations))) - # a package (with __init__.py) - elif spec.submodule_search_locations: - return os.path.dirname(os.path.dirname(spec.origin)) - # just a normal module - else: - return os.path.dirname(spec.origin) + return os.path.dirname(spec.origin) # we were unable to find the `package_path` using PEP 451 loaders loader = pkgutil.get_loader(root_mod_name) @@ -888,7 +881,6 @@ def _find_package_path(root_mod_name): # import name is not found, or interactive/main module return os.getcwd() else: - # For .egg, zipimporter does not have get_filename until Python 2.7. if hasattr(loader, "get_filename"): filename = loader.get_filename(root_mod_name) elif hasattr(loader, "archive"): diff --git a/tests/test_basic.py b/tests/test_basic.py index d1313f2f..d7e72a18 100644 --- a/tests/test_basic.py +++ b/tests/test_basic.py @@ -91,12 +91,7 @@ def test_provide_automatic_options_kwarg(app, client): assert rv.status_code == 405 assert sorted(rv.allow) == ["GET", "HEAD"] - # Older versions of Werkzeug.test.Client don't have an options method - if hasattr(client, "options"): - rv = client.options("/") - else: - rv = client.open("/", method="OPTIONS") - + rv = client.open("/", method="OPTIONS") assert rv.status_code == 405 rv = client.head("/") @@ -109,11 +104,7 @@ def test_provide_automatic_options_kwarg(app, client): assert rv.status_code == 405 assert sorted(rv.allow) == ["GET", "HEAD", "POST"] - if hasattr(client, "options"): - rv = client.options("/more") - else: - rv = client.open("/more", method="OPTIONS") - + rv = client.open("/more", method="OPTIONS") assert rv.status_code == 405 diff --git a/tests/test_cli.py b/tests/test_cli.py index a3048b91..46ebc685 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -589,16 +589,11 @@ def test_run_cert_import(monkeypatch): with pytest.raises(click.BadParameter): run_command.make_context("run", ["--cert", "not_here"]) - # not an SSLContext - if sys.version_info >= (2, 7, 9): - with pytest.raises(click.BadParameter): - run_command.make_context("run", ["--cert", "flask"]) + with pytest.raises(click.BadParameter): + run_command.make_context("run", ["--cert", "flask"]) # SSLContext - if sys.version_info < (2, 7, 9): - ssl_context = object() - else: - ssl_context = ssl.SSLContext(ssl.PROTOCOL_SSLv23) + ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLS_SERVER) monkeypatch.setitem(sys.modules, "ssl_context", ssl_context) ctx = run_command.make_context("run", ["--cert", "ssl_context"]) diff --git a/tests/test_helpers.py b/tests/test_helpers.py index eeae481b..bc982f8b 100644 --- a/tests/test_helpers.py +++ b/tests/test_helpers.py @@ -92,7 +92,6 @@ class TestJSON(object): ) def test_detect_encoding(self, value, encoding): data = json.dumps(value).encode(encoding) - assert json.detect_encoding(data) == encoding assert json.loads(data) == value @pytest.mark.parametrize("debug", (True, False)) @@ -679,8 +678,6 @@ class TestSendfile(object): "%C3%91and%C3%BA%EF%BC%8Fping%C3%BCino.txt", ), (u"Vögel.txt", "Vogel.txt", "V%C3%B6gel.txt"), - # Native string not marked as Unicode on Python 2 - ("tést.txt", "test.txt", "t%C3%A9st.txt"), # ":/" are not safe in filename* value (u"те:/ст", '":/"', "%D1%82%D0%B5%3A%2F%D1%81%D1%82"), ), diff --git a/tests/test_regression.py b/tests/test_regression.py index d5ec837c..ac05cd1b 100644 --- a/tests/test_regression.py +++ b/tests/test_regression.py @@ -9,7 +9,7 @@ :license: BSD-3-Clause """ import gc -import sys +import platform import threading import pytest @@ -44,6 +44,7 @@ class assert_no_leak(object): gc.enable() +@pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="CPython only") def test_memory_consumption(): app = flask.Flask(__name__) @@ -60,11 +61,9 @@ def test_memory_consumption(): # Trigger caches fire() - # This test only works on CPython 2.7. - if sys.version_info >= (2, 7) and not hasattr(sys, "pypy_translation_info"): - with assert_no_leak(): - for _x in range(10): - fire() + with assert_no_leak(): + for _x in range(10): + fire() def test_safe_join_toplevel_pardir(): diff --git a/tests/test_reqctx.py b/tests/test_reqctx.py index 8f00034b..75883444 100644 --- a/tests/test_reqctx.py +++ b/tests/test_reqctx.py @@ -285,10 +285,6 @@ def test_session_dynamic_cookie_name(): def test_bad_environ_raises_bad_request(): app = flask.Flask(__name__) - # We cannot use app.test_client() for the Unicode-rich Host header, - # because werkzeug enforces latin1 on Python 2. - # However it works when actually passed to the server. - from flask.testing import EnvironBuilder builder = EnvironBuilder(app) @@ -309,10 +305,6 @@ def test_environ_for_valid_idna_completes(): def index(): return "Hello World!" - # We cannot use app.test_client() for the Unicode-rich Host header, - # because werkzeug enforces latin1 on Python 2. - # However it works when actually passed to the server. - from flask.testing import EnvironBuilder builder = EnvironBuilder(app) diff --git a/tests/test_testing.py b/tests/test_testing.py index 8571115c..41c2e729 100644 --- a/tests/test_testing.py +++ b/tests/test_testing.py @@ -169,12 +169,10 @@ def test_redirect_keep_session(app, client, app_ctx): rv = client.get("/") assert rv.data == b"index" assert flask.session.get("data") == "foo" + rv = client.post("/", data={}, follow_redirects=True) assert rv.data == b"foo" - - # This support requires a new Werkzeug version - if not hasattr(client, "redirect_client"): - assert flask.session.get("data") == "foo" + assert flask.session.get("data") == "foo" rv = client.get("/getsession") assert rv.data == b"foo"