From 4d334205acc4fcd3fc31f5c98332a62091cab158 Mon Sep 17 00:00:00 2001 From: Kevin Bates Date: Tue, 24 Sep 2019 11:15:16 -0700 Subject: [PATCH] Remove Python 2 support, require 3.5+ Adjust dependencies and conditional imports/functions that distinguished between Python versions 2 and 3. --- .travis.yml | 1 - appveyor.yml | 2 -- jupyter_server/auth/login.py | 7 ++----- jupyter_server/base/handlers.py | 15 +++------------ jupyter_server/base/zmqhandlers.py | 8 ++------ jupyter_server/files/handlers.py | 5 +---- .../nbconvert/tests/test_nbconvert_handlers.py | 5 +---- jupyter_server/serverapp.py | 13 +------------ jupyter_server/services/contents/fileio.py | 15 ++------------- .../services/contents/tests/test_contents_api.py | 5 +---- jupyter_server/tests/launchserver.py | 6 +----- jupyter_server/tests/test_extensions.py | 13 ++----------- jupyter_server/tests/test_paths.py | 11 ++--------- jupyter_server/tests/test_serverapp.py | 6 +----- jupyter_server/utils.py | 6 +----- setup.py | 12 ++++++------ 16 files changed, 26 insertions(+), 104 deletions(-) diff --git a/.travis.yml b/.travis.yml index c379083a2..98c653e8b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,6 @@ cache: - $HOME/.cache/pip python: - 3.6 - - 2.7 sudo: required diff --git a/appveyor.yml b/appveyor.yml index 2b7ec9f9d..657cb2347 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -6,8 +6,6 @@ environment: matrix: - CONDA_PY: 36 CONDA_INSTALL_LOCN: "C:\\Miniconda36-x64" - - CONDA_PY: 27 - CONDA_INSTALL_LOCN: "C:\\Miniconda-x64" platform: - x64 diff --git a/jupyter_server/auth/login.py b/jupyter_server/auth/login.py index fd251c9b1..c53419bb8 100644 --- a/jupyter_server/auth/login.py +++ b/jupyter_server/auth/login.py @@ -5,13 +5,10 @@ import re import os - -try: - from urllib.parse import urlparse # Py 3 -except ImportError: - from urlparse import urlparse # Py 2 import uuid +from urllib.parse import urlparse + from tornado.escape import url_escape from .security import passwd_check, set_password diff --git a/jupyter_server/base/handlers.py b/jupyter_server/base/handlers.py index d84c8be2b..69d810099 100755 --- a/jupyter_server/base/handlers.py +++ b/jupyter_server/base/handlers.py @@ -14,18 +14,9 @@ import traceback import types import warnings -try: - # py3 - from http.client import responses - from http.cookies import Morsel -except ImportError: - from httplib import responses - from Cookie import Morsel -try: - from urllib.parse import urlparse # Py 3 -except ImportError: - from urlparse import urlparse # Py 2 - +from http.client import responses +from http.cookies import Morsel +from urllib.parse import urlparse from jinja2 import TemplateNotFound from tornado import web, gen, escape, httputil from tornado.log import app_log diff --git a/jupyter_server/base/zmqhandlers.py b/jupyter_server/base/zmqhandlers.py index 99b64f9e0..a80cb71b9 100644 --- a/jupyter_server/base/zmqhandlers.py +++ b/jupyter_server/base/zmqhandlers.py @@ -9,13 +9,9 @@ import struct import warnings import sys - -try: - from urllib.parse import urlparse # Py 3 -except ImportError: - from urlparse import urlparse # Py 2 - import tornado + +from urllib.parse import urlparse from tornado import gen, ioloop, web from tornado.websocket import WebSocketHandler diff --git a/jupyter_server/files/handlers.py b/jupyter_server/files/handlers.py index 788bfb0da..b1051ac18 100644 --- a/jupyter_server/files/handlers.py +++ b/jupyter_server/files/handlers.py @@ -6,10 +6,7 @@ import mimetypes import json -try: #PY3 - from base64 import decodebytes -except ImportError: #PY2 - from base64 import decodestring as decodebytes +from base64 import decodebytes from tornado import web diff --git a/jupyter_server/nbconvert/tests/test_nbconvert_handlers.py b/jupyter_server/nbconvert/tests/test_nbconvert_handlers.py index 956180321..d16421e03 100644 --- a/jupyter_server/nbconvert/tests/test_nbconvert_handlers.py +++ b/jupyter_server/nbconvert/tests/test_nbconvert_handlers.py @@ -16,10 +16,7 @@ from ipython_genutils.testing.decorators import onlyif_cmds_exist -try: #PY3 - from base64 import encodebytes -except ImportError: #PY2 - from base64 import encodestring as encodebytes +from base64 import encodebytes class NbconvertAPI(object): diff --git a/jupyter_server/serverapp.py b/jupyter_server/serverapp.py index e84701bbd..28f0ec843 100755 --- a/jupyter_server/serverapp.py +++ b/jupyter_server/serverapp.py @@ -31,12 +31,7 @@ import warnings import webbrowser -try: #PY3 - from base64 import encodebytes -except ImportError: #PY2 - from base64 import encodestring as encodebytes - - +from base64 import encodebytes from jinja2 import Environment, FileSystemLoader from jupyter_server.transutils import trans, _ @@ -70,12 +65,6 @@ __version__, ) -# py23 compatibility -try: - raw_input = raw_input -except NameError: - raw_input = input - from .base.handlers import MainHandler, RedirectWithParams, Template404 from .log import log_request from .services.kernels.kernelmanager import MappingKernelManager diff --git a/jupyter_server/services/contents/fileio.py b/jupyter_server/services/contents/fileio.py index c21326f3a..7e9249777 100644 --- a/jupyter_server/services/contents/fileio.py +++ b/jupyter_server/services/contents/fileio.py @@ -24,24 +24,13 @@ from traitlets.config import Configurable from traitlets import Bool -try: #PY3 - from base64 import encodebytes, decodebytes -except ImportError: #PY2 - from base64 import encodestring as encodebytes, decodestring as decodebytes +from base64 import encodebytes, decodebytes def replace_file(src, dst): """ replace dst with src - - switches between os.replace or os.rename based on python 2.7 or python 3 """ - if hasattr(os, 'replace'): # PY3 - os.replace(src, dst) - else: - if os.name == 'nt' and os.path.exists(dst): - # Rename over existing file doesn't work on Windows - os.remove(dst) - os.rename(src, dst) + os.replace(src, dst) def copy2_safe(src, dst, log=None): """copy src to dst diff --git a/jupyter_server/services/contents/tests/test_contents_api.py b/jupyter_server/services/contents/tests/test_contents_api.py index 88c348df8..f50536a7d 100644 --- a/jupyter_server/services/contents/tests/test_contents_api.py +++ b/jupyter_server/services/contents/tests/test_contents_api.py @@ -27,10 +27,7 @@ from ipython_genutils import py3compat from ipython_genutils.tempdir import TemporaryDirectory -try: #PY3 - from base64 import encodebytes, decodebytes -except ImportError: #PY2 - from base64 import encodestring as encodebytes, decodestring as decodebytes +from base64 import encodebytes, decodebytes def uniq_stable(elems): diff --git a/jupyter_server/tests/launchserver.py b/jupyter_server/tests/launchserver.py index 72c8b2562..e6a2492f8 100644 --- a/jupyter_server/tests/launchserver.py +++ b/jupyter_server/tests/launchserver.py @@ -13,11 +13,7 @@ pjoin = os.path.join -try: - from unittest.mock import patch -except ImportError: - from mock import patch #py2 - +from unittest.mock import patch import requests from tornado.ioloop import IOLoop import zmq diff --git a/jupyter_server/tests/test_extensions.py b/jupyter_server/tests/test_extensions.py index 6ce734f85..38664dd6b 100644 --- a/jupyter_server/tests/test_extensions.py +++ b/jupyter_server/tests/test_extensions.py @@ -2,10 +2,7 @@ import os import sys from unittest import TestCase -try: - from unittest.mock import patch -except ImportError: - from mock import patch # py2 +from unittest.mock import patch from ipython_genutils.tempdir import TemporaryDirectory from ipython_genutils import py3compat @@ -17,13 +14,7 @@ from jupyter_server.extensions import toggle_serverextension_python, _get_config_dir from jupyter_server import extensions, extensions_base from jupyter_server.serverapp import ServerApp - -if sys.version_info > (3,): - from types import SimpleNamespace -else: - class SimpleNamespace(object): - pass - +from types import SimpleNamespace from collections import OrderedDict def test_help_output(): diff --git a/jupyter_server/tests/test_paths.py b/jupyter_server/tests/test_paths.py index 10b4188bf..88e6d1589 100644 --- a/jupyter_server/tests/test_paths.py +++ b/jupyter_server/tests/test_paths.py @@ -4,13 +4,6 @@ from jupyter_server.base.handlers import path_regex -try: # py3 - assert_regex = nt.assert_regex - assert_not_regex = nt.assert_not_regex -except AttributeError: # py2 - assert_regex = nt.assert_regexp_matches - assert_not_regex = nt.assert_not_regexp_matches - # build regexps that tornado uses: path_pat = re.compile('^' + '/x%s' % path_regex + '$') @@ -24,7 +17,7 @@ def test_path_regex(): '/x/foo/bar', '/x/foo/bar.txt', ): - assert_regex(path, path_pat) + nt.assert_regex(path, path_pat) def test_path_regex_bad(): for path in ( @@ -37,4 +30,4 @@ def test_path_regex_bad(): '/y', '/y/x/foo', ): - assert_not_regex(path, path_pat) + nt.assert_not_regex(path, path_pat) diff --git a/jupyter_server/tests/test_serverapp.py b/jupyter_server/tests/test_serverapp.py index fad804a93..08519a186 100644 --- a/jupyter_server/tests/test_serverapp.py +++ b/jupyter_server/tests/test_serverapp.py @@ -8,11 +8,7 @@ from subprocess import Popen, PIPE, STDOUT import sys from tempfile import NamedTemporaryFile - -try: - from unittest.mock import patch -except ImportError: - from mock import patch # py2 +from unittest.mock import patch import nose.tools as nt diff --git a/jupyter_server/utils.py b/jupyter_server/utils.py index 2b560554c..5d48f7233 100644 --- a/jupyter_server/utils.py +++ b/jupyter_server/utils.py @@ -27,11 +27,7 @@ class ConcurrentFuture: """If concurrent.futures isn't importable, nothing will be a c.f.Future""" pass -try: - from urllib.parse import quote, unquote, urlparse -except ImportError: - from urllib import quote, unquote - from urlparse import urlparse +from urllib.parse import quote, unquote, urlparse # tornado.concurrent.Future is asyncio.Future # in tornado >=5 with Python 3 diff --git a/setup.py b/setup.py index 497a59c59..64e4a5ee0 100755 --- a/setup.py +++ b/setup.py @@ -19,9 +19,8 @@ name = "jupyter_server" # Minimal Python version sanity check -v = sys.version_info -if v[:2] < (2,7) or (v[0] >= 3 and v[:2] < (3,3)): - error = "ERROR: %s requires Python version 2.7 or 3.3 or above." % name +if sys.version_info < (3,5): + error = "ERROR: %s requires Python version 3.5 or above." % name print(error, file=sys.stderr) sys.exit(1) @@ -67,8 +66,10 @@ 'Intended Audience :: Science/Research', 'License :: OSI Approved :: BSD License', 'Programming Language :: Python', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', ], zip_safe = False, install_requires = [ @@ -90,12 +91,11 @@ "pywin32>=1.0 ; sys_platform == 'win32'" ], extras_require = { - ':python_version == "2.7"': ['ipaddress'], - 'test:python_version == "2.7"': ['mock'], 'test': ['nose', 'coverage', 'requests', 'nose_warnings_filters', 'nbval', 'nose-exclude', 'selenium'], 'test:sys_platform == "win32"': ['nose-exclude'], }, + python_requires='>=3.5', entry_points = { 'console_scripts': [ 'jupyter-server = jupyter_server.serverapp:main',