From 64f1ef081e29ac447cab9488dcce189c323b317e Mon Sep 17 00:00:00 2001 From: Quentin Peter Date: Sun, 12 Jun 2022 19:37:14 +0200 Subject: [PATCH] git subrepo clone (merge) --branch=profile_script --force https://github.com/impact27/spyder-kernels.git external-deps/spyder-kernels subrepo: subdir: "external-deps/spyder-kernels" merged: "667b2c921" upstream: origin: "https://github.com/impact27/spyder-kernels.git" branch: "profile_script" commit: "667b2c921" git-subrepo: version: "0.4.1" origin: "https://github.com/ingydotnet/git-subrepo" commit: "a04d8c2" --- .../.github/workflows/linux-pip-tests.yml | 2 +- .../.github/workflows/linux-tests.yml | 4 +- .../.github/workflows/macos-tests.yml | 4 +- .../.github/workflows/windows-tests.yml | 4 - external-deps/spyder-kernels/.gitrepo | 4 +- .../spyder-kernels/requirements/python-27.txt | 11 - external-deps/spyder-kernels/setup.cfg | 3 - external-deps/spyder-kernels/setup.py | 20 +- .../spyder_kernels/comms/commbase.py | 19 +- .../spyder_kernels/comms/frontendcomm.py | 25 +- .../spyder_kernels/console/kernel.py | 34 +- .../spyder_kernels/console/start.py | 53 +-- .../console/tests/test_console_kernel.py | 101 +++-- .../customize/namespace_manager.py | 5 +- .../customize/spydercustomize.py | 237 ++++-------- .../spyder_kernels/customize/spyderpdb.py | 95 +---- .../customize/tests/test_umr.py | 5 +- .../spyder_kernels/customize/umr.py | 10 +- .../spyder_kernels/py3compat.py | 360 ------------------ .../spyder_kernels/utils/dochelpers.py | 44 +-- .../spyder_kernels/utils/iofuncs.py | 31 +- .../spyder_kernels/utils/lazymodules.py | 4 +- .../spyder_kernels/utils/misc.py | 2 +- .../spyder_kernels/utils/nsview.py | 63 ++- .../utils/tests/test_dochelpers.py | 4 +- .../utils/tests/test_iofuncs.py | 5 +- .../spyder_kernels/utils/tests/test_nsview.py | 20 +- 27 files changed, 279 insertions(+), 890 deletions(-) delete mode 100644 external-deps/spyder-kernels/requirements/python-27.txt delete mode 100644 external-deps/spyder-kernels/setup.cfg delete mode 100644 external-deps/spyder-kernels/spyder_kernels/py3compat.py diff --git a/external-deps/spyder-kernels/.github/workflows/linux-pip-tests.yml b/external-deps/spyder-kernels/.github/workflows/linux-pip-tests.yml index b376c17b705..affbb561e74 100644 --- a/external-deps/spyder-kernels/.github/workflows/linux-pip-tests.yml +++ b/external-deps/spyder-kernels/.github/workflows/linux-pip-tests.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] + PYTHON_VERSION: ['3.7', '3.8', '3.9'] timeout-minutes: 20 steps: - name: Checkout branch diff --git a/external-deps/spyder-kernels/.github/workflows/linux-tests.yml b/external-deps/spyder-kernels/.github/workflows/linux-tests.yml index 63ee8b860db..4a84799d2c7 100644 --- a/external-deps/spyder-kernels/.github/workflows/linux-tests.yml +++ b/external-deps/spyder-kernels/.github/workflows/linux-tests.yml @@ -22,7 +22,7 @@ jobs: strategy: fail-fast: false matrix: - PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] + PYTHON_VERSION: ['3.7', '3.8', '3.9'] timeout-minutes: 20 steps: - name: Checkout branch @@ -43,7 +43,7 @@ jobs: - name: Install package dependencies shell: bash -l {0} run: | - if [ "$PYTHON_VERSION" != "2.7" ]; then mamba install --file requirements/posix.txt -y -q; else mamba install --file requirements/python-27.txt -y -q; fi + mamba install --file requirements/posix.txt -y -q - name: Install test dependencies shell: bash -l {0} run: mamba install --file requirements/tests.txt -y -q diff --git a/external-deps/spyder-kernels/.github/workflows/macos-tests.yml b/external-deps/spyder-kernels/.github/workflows/macos-tests.yml index 0e63b69c89e..225cd3fdad5 100644 --- a/external-deps/spyder-kernels/.github/workflows/macos-tests.yml +++ b/external-deps/spyder-kernels/.github/workflows/macos-tests.yml @@ -21,7 +21,7 @@ jobs: strategy: fail-fast: false matrix: - PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] + PYTHON_VERSION: ['3.7', '3.8', '3.9'] timeout-minutes: 25 steps: - name: Checkout branch @@ -38,7 +38,7 @@ jobs: - name: Install package dependencies shell: bash -l {0} run: | - if [ "$PYTHON_VERSION" != "2.7" ]; then mamba install --file requirements/posix.txt -y -q; else mamba install --file requirements/python-27.txt -y -q; fi + mamba install --file requirements/posix.txt -y -q - name: Install test dependencies shell: bash -l {0} run: mamba install --file requirements/tests.txt -y -q diff --git a/external-deps/spyder-kernels/.github/workflows/windows-tests.yml b/external-deps/spyder-kernels/.github/workflows/windows-tests.yml index f782e18e31a..cb6d6ac226d 100644 --- a/external-deps/spyder-kernels/.github/workflows/windows-tests.yml +++ b/external-deps/spyder-kernels/.github/workflows/windows-tests.yml @@ -50,10 +50,6 @@ jobs: run: | conda info conda list - - name: Set correct enconding - shell: bash -l {0} - if: matrix.PYTHON_VERSION == '2.7' - run: echo "::set-env name=PYTHONIOENCODING::cp1252" - name: Run tests shell: bash -l {0} run: pytest spyder_kernels --cov=spyder_kernels -x -vv || pytest spyder_kernels --cov=spyder_kernels -x -vv || pytest spyder_kernels --cov=spyder_kernels -x -vv diff --git a/external-deps/spyder-kernels/.gitrepo b/external-deps/spyder-kernels/.gitrepo index 32749a7d1c3..4e36eb3b4c2 100644 --- a/external-deps/spyder-kernels/.gitrepo +++ b/external-deps/spyder-kernels/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/spyder-ide/spyder-kernels.git branch = profile_script - commit = 7bdd81e2f37f966075b74cf3e9bf91190c0f131b - parent = 93f337977e936231e1f8b4669604cbd36f39e501 + commit = 667b2c92188187d7723fe2ec66ff89821ef15a52 + parent = a785cf65378b1f28a28ce056d471244fc9a99e91 method = merge cmdver = 0.4.1 diff --git a/external-deps/spyder-kernels/requirements/python-27.txt b/external-deps/spyder-kernels/requirements/python-27.txt deleted file mode 100644 index 9dfccfef328..00000000000 --- a/external-deps/spyder-kernels/requirements/python-27.txt +++ /dev/null @@ -1,11 +0,0 @@ -decorator<5 -backports.functools_lru_cache -cloudpickle -ipykernel<5 -jupyter_client>=5.3.4,<6 -pyzmq>=17,<20 -wurlitzer>=1.0.3 -# To avoid an error with conda -click =7 -# To avoid a problem with zict -zict <2.1.0 diff --git a/external-deps/spyder-kernels/setup.cfg b/external-deps/spyder-kernels/setup.cfg deleted file mode 100644 index e606cea4f59..00000000000 --- a/external-deps/spyder-kernels/setup.cfg +++ /dev/null @@ -1,3 +0,0 @@ -[bdist_wheel] -# Code is written to work on both Python 2 and Python 3. -universal=1 diff --git a/external-deps/spyder-kernels/setup.py b/external-deps/spyder-kernels/setup.py index 9dbb24e9724..ff3d025a781 100644 --- a/external-deps/spyder-kernels/setup.py +++ b/external-deps/spyder-kernels/setup.py @@ -36,17 +36,12 @@ def get_version(module='spyder_kernels'): REQUIREMENTS = [ - 'decorator<5; python_version<"3"', - 'backports.functools-lru-cache; python_version<"3"', 'cloudpickle', - 'ipykernel<5; python_version<"3"', - 'ipykernel>=6.9.2,<7; python_version>="3"', - 'ipython<6; python_version<"3"', - 'ipython>=7.31.1,<8; python_version>="3"', - 'jupyter-client>=5.3.4,<6; python_version<"3"', - 'jupyter-client>=7.3.1,<8; python_version>="3"', - 'pyzmq>=17,<20; python_version<"3"', - 'pyzmq>=22.1.0; python_version>="3"', + 'ipykernel>=6.9.2,<7', + 'ipython>=7.31.1,<8', + 'jupyter-client>=7.3.1,<8', + 'packaging', + 'pyzmq>=22.1.0', 'wurlitzer>=1.0.3;platform_system!="Windows"', ] @@ -82,6 +77,7 @@ def get_version(module='spyder_kernels'): install_requires=REQUIREMENTS, extras_require={'test': TEST_REQUIREMENTS}, include_package_data=True, + python_requires='>=3.7', classifiers=[ 'Development Status :: 5 - Production/Stable', 'Framework :: Jupyter', @@ -89,13 +85,11 @@ def get_version(module='spyder_kernels'): 'Intended Audience :: Developers', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Topic :: Software Development :: Interpreters', ] ) diff --git a/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py b/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py index b4dea83b1e7..650208d8225 100644 --- a/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py +++ b/external-deps/spyder-kernels/spyder_kernels/comms/commbase.py @@ -59,13 +59,10 @@ import uuid import traceback -from spyder_kernels.py3compat import PY2, PY3 - logger = logging.getLogger(__name__) -# To be able to get and set variables between Python 2 and 3 -DEFAULT_PICKLE_PROTOCOL = 2 +DEFAULT_PICKLE_PROTOCOL = 4 # Max timeout (in secs) for blocking calls TIMEOUT = 3 @@ -132,7 +129,7 @@ def comm_excepthook(type, value, tb): sys.excepthook = comm_excepthook -class CommBase(object): +class CommBase: """ Class with the necessary attributes and methods to handle communications between a kernel and a frontend. @@ -309,15 +306,7 @@ def _comm_message(self, msg): # Load the buffer. Only one is supported. try: - if PY3: - # https://docs.python.org/3/library/pickle.html#pickle.loads - # Using encoding='latin1' is required for unpickling - # NumPy arrays and instances of datetime, date and time - # pickled by Python 2. - buffer = cloudpickle.loads(msg['buffers'][0], - encoding='latin-1') - else: - buffer = cloudpickle.loads(msg['buffers'][0]) + buffer = cloudpickle.loads(msg['buffers'][0]) except Exception as e: logger.debug( "Exception in cloudpickle.loads : %s" % str(e)) @@ -496,7 +485,7 @@ def _sync_error(self, error_wrapper): error_wrapper.raise_error() -class RemoteCallFactory(object): +class RemoteCallFactory: """Class to create `RemoteCall`s.""" def __init__(self, comms_wrapper, comm_id, callback, **settings): diff --git a/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py b/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py index 09ef08638b3..04b232c7e6b 100644 --- a/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py +++ b/external-deps/spyder-kernels/spyder_kernels/comms/frontendcomm.py @@ -21,7 +21,6 @@ import zmq from spyder_kernels.comms.commbase import CommBase, CommError -from spyder_kernels.py3compat import TimeoutError, PY2 def get_free_port(): @@ -87,16 +86,15 @@ def __init__(self, kernel): self.comm_socket_thread = threading.Thread(target=self.poll_thread) self.comm_socket_thread.start() - # Patch parent.close . This function only exists in Python 3. - if not PY2: - parent_close = self.kernel.parent.close + # Patch parent.close + parent_close = self.kernel.parent.close - def close(): - """Close comm_socket_thread.""" - self.close_thread() - parent_close() + def close(): + """Close comm_socket_thread.""" + self.close_thread() + parent_close() - self.kernel.parent.close = close + self.kernel.parent.close = close def close(self, comm_id=None): """Close the comm and notify the other side.""" @@ -117,9 +115,8 @@ def close_thread(self): def poll_thread(self): """Receive messages from comm socket.""" - if not PY2: - # Create an event loop for the handlers. - ioloop.IOLoop().initialize() + # Create an event loop for the handlers. + ioloop.IOLoop().initialize() while not self.comm_thread_close.is_set(): self.poll_one() @@ -149,10 +146,6 @@ def poll_one(self): if handler is None: self.kernel.log.warning("Unknown message type: %r", msg_type) return - if PY2: - handler(out_stream, ident, msg) - return - import asyncio if (getattr(asyncio, 'run', False) and diff --git a/external-deps/spyder-kernels/spyder_kernels/console/kernel.py b/external-deps/spyder-kernels/spyder_kernels/console/kernel.py index 723795be7b8..107b7322b17 100644 --- a/external-deps/spyder-kernels/spyder_kernels/console/kernel.py +++ b/external-deps/spyder-kernels/spyder_kernels/console/kernel.py @@ -11,20 +11,17 @@ """ # Standard library imports -from distutils.version import LooseVersion +import faulthandler import logging import os import sys import threading # Third-party imports -import ipykernel from ipykernel.ipkernel import IPythonKernel from traitlets.config.loader import LazyConfigValue # Local imports -from spyder_kernels.py3compat import ( - TEXT_TYPES, to_text_string, PY3, input, TimeoutError) from spyder_kernels.comms.frontendcomm import FrontendComm, CommError from spyder_kernels.utils.iofuncs import iofunctions from spyder_kernels.utils.mpl import ( @@ -32,8 +29,6 @@ from spyder_kernels.utils.nsview import get_remote_data, make_remote_view from spyder_kernels.console.shell import SpyderShell -if PY3: - import faulthandler logger = logging.getLogger(__name__) @@ -130,9 +125,6 @@ def enable_faulthandler(self, fn): Open a file to save the faulthandling and identifiers for internal threads. """ - if not PY3: - # Not implemented - return self.disable_faulthandler() f = open(fn, 'w') self.faulthandler_handle = f @@ -148,9 +140,6 @@ def disable_faulthandler(self): """ Cancel the faulthandling, close the file handle and remove the file. """ - if not PY3: - # Not implemented - return if self.faulthandler_handle: faulthandler.disable() self.faulthandler_handle.close() @@ -383,12 +372,8 @@ def cmd_input(self, prompt=''): self.frontend_call().pdb_input(prompt) # Allow GUI event loop to update - if PY3: - is_main_thread = ( - threading.current_thread() is threading.main_thread()) - else: - is_main_thread = isinstance( - threading.current_thread(), threading._MainThread) + is_main_thread = ( + threading.current_thread() is threading.main_thread()) # Get input by running eventloop if is_main_thread and self.eventloop: @@ -505,7 +490,7 @@ def get_mpl_interactive_backend(self): def set_matplotlib_backend(self, backend, pylab=False): """Set matplotlib backend given a Spyder backend option.""" - mpl_backend = MPL_BACKENDS_FROM_SPYDER[to_text_string(backend)] + mpl_backend = MPL_BACKENDS_FROM_SPYDER[str(backend)] self._set_mpl_backend(mpl_backend, pylab=pylab) def set_mpl_inline_figure_format(self, figure_format): @@ -516,11 +501,7 @@ def set_mpl_inline_figure_format(self, figure_format): def set_mpl_inline_resolution(self, resolution): """Set inline figure resolution.""" - if LooseVersion(ipykernel.__version__) < LooseVersion('4.5'): - option = 'savefig.dpi' - else: - option = 'figure.dpi' - self._set_mpl_inline_rc_config(option, resolution) + self._set_mpl_inline_rc_config('figure.dpi', resolution) def set_mpl_inline_figure_size(self, width, height): """Set inline figure size.""" @@ -747,9 +728,8 @@ def _eval(self, text): where *obj* is the object represented by *text* and *valid* is True if object evaluation did not raise any exception """ - from spyder_kernels.py3compat import is_text_string - assert is_text_string(text) + assert isinstance(text, str) ns = self._get_current_namespace(with_magics=True) try: return eval(text, ns), True @@ -837,7 +817,7 @@ def _set_config_option(self, option, value): try: base_config = "{option} = " value_line = ( - "'{value}'" if isinstance(value, TEXT_TYPES) else "{value}") + "'{value}'" if isinstance(value, str) else "{value}") config_line = base_config + value_line get_ipython().run_line_magic( 'config', diff --git a/external-deps/spyder-kernels/spyder_kernels/console/start.py b/external-deps/spyder-kernels/spyder_kernels/console/start.py index 9f9fa7a759a..e6653f0cd2c 100644 --- a/external-deps/spyder-kernels/spyder_kernels/console/start.py +++ b/external-deps/spyder-kernels/spyder_kernels/console/start.py @@ -11,14 +11,14 @@ """ # Standard library imports -from distutils.version import LooseVersion import os import os.path as osp import sys import site +# Third-party imports +from packaging.version import parse from traitlets import DottedObjectName -import ipykernel # Local imports from spyder_kernels.utils.misc import is_module_installed @@ -26,10 +26,6 @@ MPL_BACKENDS_FROM_SPYDER, INLINE_FIGURE_FORMATS) -PY2 = sys.version[0] == '2' -IPYKERNEL_6 = ipykernel.__version__[0] >= '6' - - def import_spydercustomize(): """Import our customizations into the kernel.""" here = osp.dirname(__file__) @@ -73,7 +69,6 @@ def sympy_config(mpl_backend): def kernel_config(): """Create a config object with IPython kernel options.""" - import ipykernel from IPython.core.application import get_ipython_dir from traitlets.config.loader import Config, load_pyconfig_files @@ -98,10 +93,9 @@ def kernel_config(): # Until we implement Issue 1052 spy_cfg.InteractiveShell.xmode = 'Plain' - # Jedi completer. It's only available in Python 3 + # Jedi completer. jedi_o = os.environ.get('SPY_JEDI_O') == 'True' - if not PY2: - spy_cfg.IPCompleter.use_jedi = jedi_o + spy_cfg.IPCompleter.use_jedi = jedi_o # Clear terminal arguments input. # This needs to be done before adding the exec_lines that come from @@ -113,12 +107,11 @@ def kernel_config(): # Set our runfile in builtins here to prevent other packages shadowing it. # This started to be a problem since IPykernel 6.3.0. - if not PY2: - spy_cfg.IPKernelApp.exec_lines.append( - "import builtins; " - "builtins.runfile = builtins.spyder_runfile; " - "del builtins.spyder_runfile; del builtins" - ) + spy_cfg.IPKernelApp.exec_lines.append( + "import builtins; " + "builtins.runfile = builtins.spyder_runfile; " + "del builtins.spyder_runfile; del builtins" + ) # Prevent other libraries to change the breakpoint builtin. # This started to be a problem since IPykernel 6.3.0. @@ -144,24 +137,19 @@ def kernel_config(): spy_cfg.IPKernelApp.exec_lines.append( "get_ipython().kernel._load_wurlitzer()") - # Default inline backend configuration + # Default inline backend configuration. # This is useful to have when people doesn't # use our config system to configure the # inline backend but want to use # '%matplotlib inline' at runtime - if LooseVersion(ipykernel.__version__) < LooseVersion('4.5'): - dpi_option = 'savefig.dpi' - else: - dpi_option = 'figure.dpi' - - # The typical default figure size is too large for inline use, - # so we shrink the figure size to 6x4, and tweak fonts to - # make that fit. spy_cfg.InlineBackend.rc = { + # The typical default figure size is too large for inline use, + # so we shrink the figure size to 6x4, and tweak fonts to + # make that fit. 'figure.figsize': (6.0, 4.0), # 72 dpi matches SVG/qtconsole. # This only affects PNG export, as SVG has no dpi setting. - dpi_option: 72, + 'figure.dpi': 72, # 12pt labels get cutoff on 6x4 logplots, so use 10pt. 'font.size': 10, # 10pt still needs a little more room on the xlabel @@ -190,7 +178,8 @@ def kernel_config(): # Resolution resolution_o = os.environ.get('SPY_RESOLUTION_O') if resolution_o is not None: - spy_cfg.InlineBackend.rc[dpi_option] = float(resolution_o) + spy_cfg.InlineBackend.rc['figure.dpi'] = float( + resolution_o) # Figure size width_o = float(os.environ.get('SPY_WIDTH_O')) @@ -233,7 +222,7 @@ def kernel_config(): if autocall_o is not None: spy_cfg.ZMQInteractiveShell.autocall = int(autocall_o) - # To handle the banner by ourselves in IPython 3+ + # To handle the banner by ourselves spy_cfg.ZMQInteractiveShell.banner1 = '' # Greedy completer @@ -248,8 +237,7 @@ def kernel_config(): # Disable the new mechanism to capture and forward low-level output # in IPykernel 6. For that we have Wurlitzer. - if LooseVersion(ipykernel.__version__) >= LooseVersion('6.3.0'): - spy_cfg.IPKernelApp.capture_fd_output = False + spy_cfg.IPKernelApp.capture_fd_output = False # Merge IPython and Spyder configs. Spyder prefs will have prevalence # over IPython ones @@ -307,9 +295,8 @@ def main(): class SpyderKernelApp(IPKernelApp): - if IPYKERNEL_6: - outstream_class = DottedObjectName( - 'spyder_kernels.console.outstream.TTYOutStream') + outstream_class = DottedObjectName( + 'spyder_kernels.console.outstream.TTYOutStream') def init_pdb(self): """ diff --git a/external-deps/spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py b/external-deps/spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py index 87cf1f43bb2..be2f7aebeb7 100644 --- a/external-deps/spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py +++ b/external-deps/spyder-kernels/spyder_kernels/console/tests/test_console_kernel.py @@ -30,7 +30,6 @@ import numpy as np # Local imports -from spyder_kernels.py3compat import PY2, PY3, to_text_string from spyder_kernels.utils.iofuncs import iofunctions from spyder_kernels.utils.mpl import MPL_BACKENDS_FROM_SPYDER from spyder_kernels.utils.test_utils import get_kernel, get_log_text @@ -56,7 +55,7 @@ def setup_kernel(cmd): """start an embedded kernel in a subprocess, and wait for it to be ready This function was taken from the ipykernel project. - We plan to remove it when dropping support for python 2. + We plan to remove it. Yields ------- @@ -77,8 +76,6 @@ def setup_kernel(cmd): if kernel.poll() is not None: o,e = kernel.communicate() - if not PY3 and isinstance(e, bytes): - e = e.decode() raise IOError("Kernel failed to start:\n%s" % e) if not os.path.exists(connection_file): @@ -95,8 +92,7 @@ def setup_kernel(cmd): finally: client.stop_channels() finally: - if not PY2: - kernel.terminate() + kernel.terminate() # ============================================================================= @@ -199,11 +195,7 @@ def test_get_namespace_view(kernel): assert "'size': 1" in nsview assert "'view': '1'" in nsview assert "'numpy_type': 'Unknown'" in nsview - - if PY3: - assert "'python_type': 'int'" in nsview - else: - assert "'python_type': u'int'" in nsview + assert "'python_type': 'int'" in nsview def test_get_var_properties(kernel): @@ -388,7 +380,7 @@ def test_get_doc(kernel): def test_get_source(kernel): """Test to get object source.""" objtxt = 'help' - assert 'class _Helper(object):' in kernel.get_source(objtxt) + assert 'class _Helper' in kernel.get_source(objtxt) # --- Other stuff @@ -439,11 +431,9 @@ def test_cwd_in_sys_path(): @flaky(max_runs=3) -@pytest.mark.skipif(not PY3, - reason="Only meant for Python 3") def test_multiprocessing(tmpdir): """ - Test that multiprocessing works on Python 3. + Test that multiprocessing works. """ # Command to start the kernel cmd = "from spyder_kernels.console import start; start.main()" @@ -468,7 +458,7 @@ def f(x): p.write(code) # Run code - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the `result` variable is defined @@ -481,11 +471,9 @@ def f(x): @flaky(max_runs=3) -@pytest.mark.skipif(not PY3, - reason="Only meant for Python 3") def test_multiprocessing_2(tmpdir): """ - Test that multiprocessing works on Python 3. + Test that multiprocessing works. """ # Command to start the kernel cmd = "from spyder_kernels.console import start; start.main()" @@ -515,7 +503,7 @@ def myFunc(i): p.write(code) # Run code - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the `result` variable is defined @@ -529,11 +517,9 @@ def myFunc(i): @flaky(max_runs=3) -@pytest.mark.skipif(not PY3, - reason="Only meant for Python 3") def test_dask_multiprocessing(tmpdir): """ - Test that dask multiprocessing works on Python 3. + Test that dask multiprocessing works. """ # Command to start the kernel cmd = "from spyder_kernels.console import start; start.main()" @@ -557,10 +543,10 @@ def test_dask_multiprocessing(tmpdir): p.write(code) # Run code two times - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the `x` variable is defined @@ -586,12 +572,12 @@ def test_runfile(tmpdir): client.get_shell_msg(timeout=TIMEOUT) # Write defined variable code to a file - code = u"result = 'hello world'; error # make an error" + code = "result = 'hello world'; error # make an error" d = tmpdir.join("defined-test.py") d.write(code) # Write undefined variable code to a file - code = dedent(u""" + code = dedent(""" try: result3 = result except NameError: @@ -602,7 +588,7 @@ def test_runfile(tmpdir): # Run code file `d` to define `result` even after an error client.execute("runfile(r'{}', current_namespace=False)" - .format(to_text_string(d))) + .format(str(d))) client.get_shell_msg(timeout=TIMEOUT) # Verify that `result` is defined in the current namespace @@ -615,7 +601,7 @@ def test_runfile(tmpdir): # Run code file `u` without current namespace client.execute("runfile(r'{}', current_namespace=False)" - .format(to_text_string(u))) + .format(str(u))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the variable `result2` is defined @@ -628,7 +614,7 @@ def test_runfile(tmpdir): # Run code file `u` with current namespace client.execute("runfile(r'{}', current_namespace=True)" - .format(to_text_string(u))) + .format(str(u))) msg = client.get_shell_msg(timeout=TIMEOUT) content = msg['content'] @@ -763,7 +749,7 @@ def test_turtle_launch(tmpdir): p.write(code) # Run code - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the `tess` variable is defined @@ -781,7 +767,7 @@ def test_turtle_launch(tmpdir): p.write(code) # Run code again - client.execute("runfile(r'{}')".format(to_text_string(p))) + client.execute("runfile(r'{}')".format(str(p))) client.get_shell_msg(timeout=TIMEOUT) # Verify that the `a` variable is defined @@ -948,12 +934,6 @@ def test_namespaces_in_pdb(kernel): pdb_obj.default("globals()['test2'] = 0") assert pdb_obj.curframe.f_globals["test2"] == 0 - if PY2: - # no error method in py2 - pdb_obj.curframe = None - pdb_obj.curframe_locals = None - return - # Create wrapper to check for errors old_error = pdb_obj.error pdb_obj._error_occured = False @@ -1096,9 +1076,6 @@ def test_locals_globals_in_pdb(kernel): @flaky(max_runs=3) @pytest.mark.parametrize("backend", [None, 'inline', 'tk', 'qt5']) -@pytest.mark.skipif( - not sys.platform.startswith('linux'), - reason="Doesn't work reliably on Windows and Mac") @pytest.mark.skipif( not bool(os.environ.get('USE_CONDA')), reason="Doesn't work with pip packages") @@ -1137,5 +1114,47 @@ def test_get_interactive_backend(backend): assert value == '0' +def test_global_message(tmpdir): + """ + Test that using `global` triggers a warning. + """ + # Command to start the kernel + cmd = "from spyder_kernels.console import start; start.main()" + + with setup_kernel(cmd) as client: + # Remove all variables + client.execute("%reset -f") + client.get_shell_msg(timeout=TIMEOUT) + + # Write code with a global to a file + code = ( + "def foo1():\n" + " global x\n" + " x = 2\n" + "x = 1\n" + "print(x)\n" + ) + + p = tmpdir.join("test.py") + p.write(code) + + # Run code in current namespace + client.execute("runfile(r'{}', current_namespace=True)".format( + str(p))) + msg = client.get_iopub_msg(timeout=TIMEOUT) + while "text" not in msg["content"]: + msg = client.get_iopub_msg(timeout=TIMEOUT) + assert "WARNING: This file contains a global statement" not in ( + msg["content"]["text"]) + + # Run code in empty namespace + client.execute("runfile(r'{}')".format(str(p))) + msg = client.get_iopub_msg(timeout=TIMEOUT) + while "text" not in msg["content"]: + msg = client.get_iopub_msg(timeout=TIMEOUT) + assert "WARNING: This file contains a global statement" in ( + msg["content"]["text"]) + + if __name__ == "__main__": pytest.main() diff --git a/external-deps/spyder-kernels/spyder_kernels/customize/namespace_manager.py b/external-deps/spyder-kernels/spyder_kernels/customize/namespace_manager.py index 2e45e4638fd..5c103804646 100755 --- a/external-deps/spyder-kernels/spyder_kernels/customize/namespace_manager.py +++ b/external-deps/spyder-kernels/spyder_kernels/customize/namespace_manager.py @@ -10,10 +10,8 @@ from IPython.core.getipython import get_ipython -from spyder_kernels.py3compat import PY2 - -class NamespaceManager(object): +class NamespaceManager: """ Get a namespace and set __file__ to filename for this namespace. @@ -65,7 +63,6 @@ def __enter__(self): self.ns_globals, self.ns_locals) if (self._file_code is not None - and not PY2 and isinstance(self._file_code, bytes)): try: self._file_code = self._file_code.decode() diff --git a/external-deps/spyder-kernels/spyder_kernels/customize/spydercustomize.py b/external-deps/spyder-kernels/spyder_kernels/customize/spydercustomize.py index 4d3a8edcf42..1f7e4000fd2 100644 --- a/external-deps/spyder-kernels/spyder_kernels/customize/spydercustomize.py +++ b/external-deps/spyder-kernels/spyder_kernels/customize/spydercustomize.py @@ -13,6 +13,7 @@ import ast import bdb +import builtins import cmd import contextlib import cProfile @@ -29,22 +30,16 @@ from IPython import __version__ as ipy_version from IPython.core.getipython import get_ipython +from IPython.core.inputtransformer2 import ( + TransformerManager, leading_indent, leading_empty_lines) from spyder_kernels.comms.frontendcomm import CommError, frontend_request from spyder_kernels.customize.namespace_manager import NamespaceManager from spyder_kernels.customize.spyderpdb import SpyderPdb, get_new_debugger from spyder_kernels.customize.umr import UserModuleReloader -from spyder_kernels.py3compat import ( - TimeoutError, PY2, _print, encode, compat_exec, FileNotFoundError) from spyder_kernels.customize.utils import ( capture_last_Expr, normalise_filename, create_pathlist) -if not PY2: - from IPython.core.inputtransformer2 import ( - TransformerManager, leading_indent, leading_empty_lines) -else: - from IPython.core.inputsplitter import IPythonInputSplitter - logger = logging.getLogger(__name__) @@ -64,42 +59,7 @@ IS_EXT_INTERPRETER = os.environ.get('SPY_EXTERNAL_INTERPRETER') == "True" HIDE_CMD_WINDOWS = os.environ.get('SPY_HIDE_CMD') == "True" SHOW_INVALID_SYNTAX_MSG = True - - -# ============================================================================= -# Execfile functions -# -# The definitions for Python 2 on Windows were taken from the IPython project -# Copyright (C) The IPython Development Team -# Distributed under the terms of the modified BSD license -# ============================================================================= -try: - # Python 2 - import __builtin__ as builtins - -except ImportError: - # Python 3 - import builtins - basestring = (str,) - - -# ============================================================================= -# Setting console encoding (otherwise Python does not recognize encoding) -# for Windows platforms -# ============================================================================= -if os.name == 'nt' and PY2: - try: - import locale, ctypes - _t, _cp = locale.getdefaultlocale('LANG') - try: - _cp = int(_cp[2:]) - ctypes.windll.kernel32.SetConsoleCP(_cp) - ctypes.windll.kernel32.SetConsoleOutputCP(_cp) - except (ValueError, TypeError): - # Code page number in locale is not valid - pass - except Exception: - pass +SHOW_GLOBAL_MSG = True # ============================================================================= @@ -127,17 +87,6 @@ def __init__(self, *args, **kwargs): pass -# ============================================================================= -# Add default filesystem encoding on Linux to avoid an error with -# Matplotlib 1.5 in Python 2 (Fixes Issue 2793) -# ============================================================================= -if PY2 and sys.platform.startswith('linux'): - def _getfilesystemencoding_wrapper(): - return 'utf-8' - - sys.getfilesystemencoding = _getfilesystemencoding_wrapper - - # ============================================================================= # Set PyQt API to #2 # ============================================================================= @@ -286,39 +235,37 @@ def spyder_bye(): # ============================================================================= # Multiprocessing adjustments # ============================================================================= -# This patch is only needed on Python 3 -if not PY2: - # This could fail with changes in Python itself, so we protect it - # with a try/except - try: - import multiprocessing.spawn - _old_preparation_data = multiprocessing.spawn.get_preparation_data - - def _patched_preparation_data(name): - """ - Patched get_preparation_data to work when all variables are - removed before execution. - """ - try: - d = _old_preparation_data(name) - except AttributeError: - main_module = sys.modules['__main__'] - # Any string for __spec__ does the job - main_module.__spec__ = '' - d = _old_preparation_data(name) - # On windows, there is no fork, so we need to save the main file - # and import it - if (os.name == 'nt' and 'init_main_from_path' in d - and not os.path.exists(d['init_main_from_path'])): - _print( - "Warning: multiprocessing may need the main file to exist. " - "Please save {}".format(d['init_main_from_path'])) - # Remove path as the subprocess can't do anything with it - del d['init_main_from_path'] - return d - multiprocessing.spawn.get_preparation_data = _patched_preparation_data - except Exception: - pass +# This could fail with changes in Python itself, so we protect it +# with a try/except +try: + import multiprocessing.spawn + _old_preparation_data = multiprocessing.spawn.get_preparation_data + + def _patched_preparation_data(name): + """ + Patched get_preparation_data to work when all variables are + removed before execution. + """ + try: + d = _old_preparation_data(name) + except AttributeError: + main_module = sys.modules['__main__'] + # Any string for __spec__ does the job + main_module.__spec__ = '' + d = _old_preparation_data(name) + # On windows, there is no fork, so we need to save the main file + # and import it + if (os.name == 'nt' and 'init_main_from_path' in d + and not os.path.exists(d['init_main_from_path'])): + print( + "Warning: multiprocessing may need the main file to exist. " + "Please save {}".format(d['init_main_from_path'])) + # Remove path as the subprocess can't do anything with it + del d['init_main_from_path'] + return d + multiprocessing.spawn.get_preparation_data = _patched_preparation_data +except Exception: + pass # ============================================================================= @@ -339,11 +286,7 @@ def cmd_input(prompt=''): pdb.Pdb = SpyderPdb - -if PY2: - cmd.raw_input = cmd_input -else: - cmd.input = cmd_input +cmd.input = cmd_input # ============================================================================= @@ -367,9 +310,9 @@ def post_mortem_excepthook(type, value, tb): if not type == SyntaxError: # wait for stderr to print (stderr.flush does not work in this case) time.sleep(0.1) - _print('*' * 40) - _print('Entering post mortem debugging...') - _print('*' * 40) + print('*' * 40) + print('Entering post mortem debugging...') + print('*' * 40) # add ability to move between frames p.send_initial_notification = False p.reset() @@ -387,19 +330,16 @@ def get_current_file_name(): try: return frontend_request(blocking=True).current_filename() except Exception: - _print("This command failed to be executed because an error occurred" - " while trying to get the current file name from Spyder's" - " editor. The error was:\n\n") + print("This command failed to be executed because an error occurred" + " while trying to get the current file name from Spyder's" + " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return None def count_leading_empty_lines(cell): """Count the number of leading empty cells.""" - if PY2: - lines = cell.splitlines(True) - else: - lines = cell.splitlines(keepends=True) + lines = cell.splitlines(keepends=True) if not lines: return 0 for i, line in enumerate(lines): @@ -412,38 +352,28 @@ def transform_cell(code, indent_only=False): """Transform IPython code to Python code.""" number_empty_lines = count_leading_empty_lines(code) if indent_only: - # Not implemented for PY2 - if PY2: - return code if not code.endswith('\n'): code += '\n' # Ensure the cell has a trailing newline lines = code.splitlines(keepends=True) lines = leading_indent(leading_empty_lines(lines)) code = ''.join(lines) else: - if PY2: - tm = IPythonInputSplitter() - return tm.transform_cell(code) - else: - tm = TransformerManager() - code = tm.transform_cell(code) + tm = TransformerManager() + code = tm.transform_cell(code) return '\n' * number_empty_lines + code def exec_code(code, filename, ns_globals, ns_locals=None, post_mortem=False, - exec_fun=None, capture_last_expression=False): + exec_fun=None, capture_last_expression=False, + global_warning=False): """Execute code and display any exception.""" # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True global SHOW_INVALID_SYNTAX_MSG - - if PY2: - filename = encode(filename) - code = encode(code) + global SHOW_GLOBAL_MSG if exec_fun is None: - # Replace by exec when dropping Python 2 - exec_fun = compat_exec + exec_fun = exec ipython_shell = get_ipython() is_ipython = os.path.splitext(filename)[1] == '.ipy' @@ -457,15 +387,10 @@ def exec_code(code, filename, ns_globals, ns_locals=None, post_mortem=False, try: ast_code = ast.parse(transform_cell(code)) except SyntaxError: - if PY2: - raise e - else: - # Need to call exec to avoid Syntax Error in Python 2. - # TODO: remove exec when dropping Python 2 support. - exec("raise e from None") + raise e from None else: if SHOW_INVALID_SYNTAX_MSG: - _print( + print( "\nWARNING: This is not valid Python code. " "If you want to use IPython magics, " "flexible indentation, and prompt removal, " @@ -475,6 +400,22 @@ def exec_code(code, filename, ns_globals, ns_locals=None, post_mortem=False, else: ast_code = ast.parse(transform_cell(code)) + # Print warning for global + if global_warning and SHOW_GLOBAL_MSG: + has_global = any( + isinstance(node, ast.Global) for node in ast.walk(ast_code)) + if has_global: + print( + "\nWARNING: This file contains a global statement, " + "but it is run in an empty namespace. " + "Consider using the " + "'Run in console's namespace instead of an empty one' " + "option, that you can find in the menu 'Run > " + "Configuration per file', if you want to capture the " + "namespace.\n" + ) + SHOW_GLOBAL_MSG = False + if code.rstrip()[-1] == ";": # Supress output with ; capture_last_expression = False @@ -554,29 +495,21 @@ def _exec_file(filename=None, args=None, wdir=None, namespace=None, if os.name == 'nt': filename = filename.replace('/', '\\') - try: - filename = filename.decode('utf-8') - except (UnicodeError, TypeError, AttributeError): - # UnicodeError, TypeError --> eventually raised in Python 2 - # AttributeError --> systematically raised in Python 3 - pass - if PY2: - filename = encode(filename) if __umr__.enabled: __umr__.run() - if args is not None and not isinstance(args, basestring): + if args is not None and not isinstance(args, str): raise TypeError("expected a character buffer object") try: file_code = get_file_code(filename) except Exception: - _print( + print( "This command failed to be executed because an error occurred" " while trying to get the file code from Spyder's" " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return if file_code is None: - _print("Could not get code from editor.\n") + print("Could not get code from editor.\n") return # Normalise the filename @@ -599,12 +532,6 @@ def _exec_file(filename=None, args=None, wdir=None, namespace=None, pass if wdir is not None: - if PY2: - try: - wdir = wdir.decode('utf-8') - except (UnicodeError, TypeError): - # UnicodeError, TypeError --> eventually raised in Python 2 - pass if os.path.isdir(wdir): os.chdir(wdir) # See https://github.com/spyder-ide/spyder/issues/13632 @@ -616,7 +543,7 @@ def _exec_file(filename=None, args=None, wdir=None, namespace=None, except Exception: pass else: - _print("Working directory {} doesn't exist.\n".format(wdir)) + print("Working directory {} doesn't exist.\n".format(wdir)) try: if __umr__.has_cython: @@ -626,7 +553,8 @@ def _exec_file(filename=None, args=None, wdir=None, namespace=None, else: exec_code(file_code, filename, ns_globals, ns_locals, post_mortem=post_mortem, exec_fun=exec_fun, - capture_last_expression=False) + capture_last_expression=False, + global_warning=not current_namespace) finally: sys.argv = [''] @@ -634,10 +562,7 @@ def _exec_file(filename=None, args=None, wdir=None, namespace=None, # IPykernel 6.3.0+ shadows our runfile because it depends on the Pydev # debugger, which adds its own runfile to builtins. So we replace it with # our own using exec_lines in start.py -if PY2: - builtins.runfile = runfile -else: - builtins.spyder_runfile = runfile +builtins.spyder_runfile = runfile def debugfile(filename=None, args=None, wdir=None, post_mortem=False, @@ -750,26 +675,20 @@ def _exec_cell(cellname, filename=None, post_mortem=False, stack_depth=0, # Otherwise code caching doesn't work if os.name == 'nt': filename = filename.replace('/', '\\') - try: - filename = filename.decode('utf-8') - except (UnicodeError, TypeError, AttributeError): - # UnicodeError, TypeError --> eventually raised in Python 2 - # AttributeError --> systematically raised in Python 3 - pass ipython_shell = get_ipython() try: # Get code from spyder cell_code = frontend_request( blocking=True).run_cell(cellname, filename) except Exception: - _print("This command failed to be executed because an error occurred" - " while trying to get the cell code from Spyder's" - " editor. The error was:\n\n") + print("This command failed to be executed because an error occurred" + " while trying to get the cell code from Spyder's" + " editor. The error was:\n\n") get_ipython().showtraceback(exception_only=True) return if not cell_code or cell_code.strip() == '': - _print("Nothing to execute, this cell is empty.\n") + print("Nothing to execute, this cell is empty.\n") return # Trigger `post_execute` to exit the additional pre-execution. diff --git a/external-deps/spyder-kernels/spyder_kernels/customize/spyderpdb.py b/external-deps/spyder-kernels/spyder_kernels/customize/spyderpdb.py index fdcbe3109fc..ae677c3c0ed 100755 --- a/external-deps/spyder-kernels/spyder_kernels/customize/spyderpdb.py +++ b/external-deps/spyder-kernels/spyder_kernels/customize/spyderpdb.py @@ -8,6 +8,7 @@ import ast import bdb +import builtins import logging import os import sys @@ -17,24 +18,16 @@ from IPython.core.autocall import ZMQExitAutocall from IPython.core.debugger import Pdb as ipyPdb from IPython.core.getipython import get_ipython +from IPython.core.inputtransformer2 import TransformerManager from spyder_kernels.comms.frontendcomm import CommError, frontend_request from spyder_kernels.customize.utils import path_is_library, capture_last_Expr -from spyder_kernels.py3compat import TimeoutError, PY2, _print, isidentifier - -if not PY2: - from IPython.core.inputtransformer2 import TransformerManager - import builtins - basestring = (str,) -else: - import __builtin__ as builtins - from IPython.core.inputsplitter import IPythonInputSplitter as TransformerManager logger = logging.getLogger(__name__) -class DebugWrapper(object): +class DebugWrapper: """ Notifies the frontend when debugging starts/stops """ @@ -62,7 +55,7 @@ def __exit__(self, exc_type, exc_val, exc_tb): logger.debug("Could not send debugging state to the frontend.") -class SpyderPdb(ipyPdb, object): # Inherits `object` to call super() in PY2 +class SpyderPdb(ipyPdb): """ Extends Pdb to add features: @@ -217,7 +210,7 @@ def default(self, line): # Load locals if they have a valid name # In comprehensions, locals could contain ".0" for example code += [indent + "{k} = _spyderpdb_locals['{k}']".format( - k=k) for k in locals if isidentifier(k)] + k=k) for k in locals if k.isidentifier()] # Update the locals @@ -262,23 +255,14 @@ def default(self, line): sys.stdin = save_stdin sys.displayhook = save_displayhook except BaseException: - if PY2: - t, v = sys.exc_info()[:2] - if type(t) == type(''): - exc_type_name = t - else: exc_type_name = t.__name__ - print >>self.stdout, '***', exc_type_name + ':', v - else: - exc_info = sys.exc_info()[:2] - self.error( - traceback.format_exception_only(*exc_info)[-1].strip()) + exc_info = sys.exc_info()[:2] + self.error( + traceback.format_exception_only(*exc_info)[-1].strip()) # --- Methods overriden for signal handling def sigint_handler(self, signum, frame): """ Handle a sigint signal. Break on the frame above this one. - - This method is not present in python2 so this won't be called there. """ if self.allow_kbdint: raise KeyboardInterrupt @@ -405,7 +389,7 @@ def is_name_or_composed(text): if not text or text[0] == '.': return False # We want to keep value.subvalue - return isidentifier(text.replace('.', '')) + return text.replace('.', '').isidentifier() while text and not is_name_or_composed(text): text = text[1:] @@ -508,7 +492,7 @@ def is_name_or_composed(text): if not text or text[0] == '.': return False # We want to keep value.subvalue - return isidentifier(text.replace('.', '')) + return text.replace('.', '').isidentifier() while text and not is_name_or_composed(text): text = text[1:] @@ -587,16 +571,9 @@ def do_debug(self, arg): try: super(SpyderPdb, self).do_debug(arg) except Exception: - if PY2: - t, v = sys.exc_info()[:2] - if type(t) == type(''): - exc_type_name = t - else: exc_type_name = t.__name__ - print >>self.stdout, '***', exc_type_name + ':', v - else: - exc_info = sys.exc_info()[:2] - self.error( - traceback.format_exception_only(*exc_info)[-1].strip()) + exc_info = sys.exc_info()[:2] + self.error( + traceback.format_exception_only(*exc_info)[-1].strip()) get_ipython().pdb_session = self def user_return(self, frame, return_value): @@ -621,9 +598,9 @@ def _cmdloop(self): self.allow_kbdint = False break except KeyboardInterrupt: - _print("--KeyboardInterrupt--\n" - "For copying text while debugging, use Ctrl+Shift+C", - file=self.stdout) + print("--KeyboardInterrupt--\n" + "For copying text while debugging, use Ctrl+Shift+C", + file=self.stdout) def precmd(self, line): """ @@ -649,39 +626,6 @@ def postcmd(self, stop, line): self.notify_spyder() return super(SpyderPdb, self).postcmd(stop, line) - if PY2: - def break_here(self, frame): - """ - Breakpoints don't work for files with non-ascii chars in Python 2 - - Fixes Issue 1484 - """ - from bdb import effective - filename = self.canonic(frame.f_code.co_filename) - try: - filename = unicode(filename, "utf-8") - except TypeError: - pass - if filename not in self.breaks: - return False - lineno = frame.f_lineno - if lineno not in self.breaks[filename]: - # The line itself has no breakpoint, but maybe the line is the - # first line of a function with breakpoint set by function name - lineno = frame.f_code.co_firstlineno - if lineno not in self.breaks[filename]: - return False - - # flag says ok to delete temp. bp - (bp, flag) = effective(filename, lineno, frame) - if bp: - self.currentbp = bp.number - if (flag and bp.temporary): - self.do_clear(str(bp.number)) - return True - else: - return False - # --- Methods defined by us for Spyder integration def set_spyder_breakpoints(self, breakpoints): """Set Spyder breakpoints.""" @@ -752,16 +696,11 @@ def notify_spyder(self): # Get filename and line number of the current frame fname = self.canonic(frame.f_code.co_filename) - if PY2: - try: - fname = unicode(fname, "utf-8") - except TypeError: - pass lineno = frame.f_lineno # Set step of the current frame (if any) step = {} - if isinstance(fname, basestring) and isinstance(lineno, int): + if isinstance(fname, str) and isinstance(lineno, int): step = dict(fname=fname, lineno=lineno) get_ipython().kernel.publish_pdb_state(step) diff --git a/external-deps/spyder-kernels/spyder_kernels/customize/tests/test_umr.py b/external-deps/spyder-kernels/spyder_kernels/customize/tests/test_umr.py index fc3329ac5f8..438f7effe4c 100644 --- a/external-deps/spyder-kernels/spyder_kernels/customize/tests/test_umr.py +++ b/external-deps/spyder-kernels/spyder_kernels/customize/tests/test_umr.py @@ -16,15 +16,14 @@ import pytest # Local imports -from spyder_kernels.py3compat import to_text_string from spyder_kernels.customize.umr import UserModuleReloader @pytest.fixture def user_module(tmpdir): """Create a simple module in tmpdir as an example of a user module.""" - if to_text_string(tmpdir) not in sys.path: - sys.path.append(to_text_string(tmpdir)) + if str(tmpdir) not in sys.path: + sys.path.append(str(tmpdir)) def create_module(modname): modfile = tmpdir.mkdir(modname).join('bar.py') diff --git a/external-deps/spyder-kernels/spyder_kernels/customize/umr.py b/external-deps/spyder-kernels/spyder_kernels/customize/umr.py index 6b71abf068f..53b80ca06f5 100644 --- a/external-deps/spyder-kernels/spyder_kernels/customize/umr.py +++ b/external-deps/spyder-kernels/spyder_kernels/customize/umr.py @@ -9,10 +9,9 @@ import sys from spyder_kernels.customize.utils import path_is_library -from spyder_kernels.py3compat import PY2, _print -class UserModuleReloader(object): +class UserModuleReloader: """ User Module Reloader (UMR) aims at deleting user modules to force Python to deeply reload them during import @@ -43,9 +42,6 @@ def __init__(self, namelist=None, pathlist=None): # pythoncom: See spyder-ide/spyder#7190 # tensorflow: See spyder-ide/spyder#8697 other_modules = ['pytorch', 'pythoncom', 'tensorflow'] - if PY2: - py2_modules = ['astropy', 'fastmat'] - other_modules = other_modules + py2_modules self.namelist = namelist + spy_modules + mpl_modules + other_modules self.pathlist = pathlist @@ -139,5 +135,5 @@ def run(self): # Report reloaded modules if self.verbose and self.modnames_to_reload: modnames = self.modnames_to_reload - _print("\x1b[4;33m%s\x1b[24m%s\x1b[0m" - % ("Reloaded modules", ": "+", ".join(modnames))) \ No newline at end of file + print("\x1b[4;33m%s\x1b[24m%s\x1b[0m" + % ("Reloaded modules", ": "+", ".join(modnames))) \ No newline at end of file diff --git a/external-deps/spyder-kernels/spyder_kernels/py3compat.py b/external-deps/spyder-kernels/spyder_kernels/py3compat.py deleted file mode 100644 index dfb0e322bbf..00000000000 --- a/external-deps/spyder-kernels/spyder_kernels/py3compat.py +++ /dev/null @@ -1,360 +0,0 @@ -# -*- coding: utf-8 -*- -# ----------------------------------------------------------------------------- -# Copyright (c) 2009- Spyder Kernels Contributors -# -# Licensed under the terms of the MIT License -# (see spyder_kernels/__init__.py for details) -# ----------------------------------------------------------------------------- - -""" -spyder.py3compat ----------------- - -Transitional module providing compatibility functions intended to help -migrating from Python 2 to Python 3. - -This module should be fully compatible with: - * Python >=v2.6 - * Python 3 -""" - -from __future__ import print_function - -import operator -import os -import sys - -PY2 = sys.version[0] == '2' -PY3 = sys.version[0] == '3' - -if PY3: - # keep reference to builtin_mod because the kernel overrides that value - # to forward requests to a frontend. - def input(prompt=''): - return builtin_mod.input(prompt) - builtin_mod_name = "builtins" - import builtins as builtin_mod -else: - # keep reference to builtin_mod because the kernel overrides that value - # to forward requests to a frontend. - def input(prompt=''): - return builtin_mod.raw_input(prompt) - builtin_mod_name = "__builtin__" - import __builtin__ as builtin_mod - - -#============================================================================== -# Data types -#============================================================================== -if PY2: - # Python 2 - TEXT_TYPES = (str, unicode) - INT_TYPES = (int, long) -else: - # Python 3 - TEXT_TYPES = (str,) - INT_TYPES = (int,) -NUMERIC_TYPES = tuple(list(INT_TYPES) + [float, complex]) - - -#============================================================================== -# Renamed/Reorganized modules -#============================================================================== -if PY2: - # Python 2 - import __builtin__ as builtins - import ConfigParser as configparser - try: - import _winreg as winreg - except ImportError: - pass - from sys import maxint as maxsize - try: - import CStringIO as io - except ImportError: - import StringIO as io - try: - import cPickle as pickle - except ImportError: - import pickle - from UserDict import DictMixin as MutableMapping - import thread as _thread - import repr as reprlib - import Queue -else: - # Python 3 - import builtins - import configparser - try: - import winreg - except ImportError: - pass - from sys import maxsize - import io - import pickle - from collections.abc import MutableMapping - import _thread - import reprlib - import queue as Queue - - -#============================================================================== -# Strings -#============================================================================== -def is_type_text_string(obj): - """Return True if `obj` is type text string, False if it is anything else, - like an instance of a class that extends the basestring class.""" - if PY2: - # Python 2 - return type(obj) in [str, unicode] - else: - # Python 3 - return type(obj) in [str, bytes] - -def is_text_string(obj): - """Return True if `obj` is a text string, False if it is anything else, - like binary data (Python 3) or QString (Python 2, PyQt API #1)""" - if PY2: - # Python 2 - return isinstance(obj, basestring) - else: - # Python 3 - return isinstance(obj, str) - -def is_binary_string(obj): - """Return True if `obj` is a binary string, False if it is anything else""" - if PY2: - # Python 2 - return isinstance(obj, str) - else: - # Python 3 - return isinstance(obj, bytes) - -def is_string(obj): - """Return True if `obj` is a text or binary Python string object, - False if it is anything else, like a QString (Python 2, PyQt API #1)""" - return is_text_string(obj) or is_binary_string(obj) - -def is_unicode(obj): - """Return True if `obj` is unicode""" - if PY2: - # Python 2 - return isinstance(obj, unicode) - else: - # Python 3 - return isinstance(obj, str) - -def to_text_string(obj, encoding=None): - """Convert `obj` to (unicode) text string""" - if PY2: - # Python 2 - if encoding is None: - return unicode(obj) - else: - return unicode(obj, encoding) - else: - # Python 3 - if encoding is None: - return str(obj) - elif isinstance(obj, str): - # In case this function is not used properly, this could happen - return obj - else: - return str(obj, encoding) - -def to_binary_string(obj, encoding=None): - """Convert `obj` to binary string (bytes in Python 3, str in Python 2)""" - if PY2: - # Python 2 - if encoding is None: - return str(obj) - else: - return obj.encode(encoding) - else: - # Python 3 - return bytes(obj, 'utf-8' if encoding is None else encoding) - - -#============================================================================== -# Function attributes -#============================================================================== -def get_func_code(func): - """Return function code object""" - if PY2: - # Python 2 - return func.func_code - else: - # Python 3 - return func.__code__ - -def get_func_name(func): - """Return function name""" - if PY2: - # Python 2 - return func.func_name - else: - # Python 3 - return func.__name__ - -def get_func_defaults(func): - """Return function default argument values""" - if PY2: - # Python 2 - return func.func_defaults - else: - # Python 3 - return func.__defaults__ - - -#============================================================================== -# Special method attributes -#============================================================================== -def get_meth_func(obj): - """Return method function object""" - if PY2: - # Python 2 - return obj.im_func - else: - # Python 3 - return obj.__func__ - -def get_meth_class_inst(obj): - """Return method class instance""" - if PY2: - # Python 2 - return obj.im_self - else: - # Python 3 - return obj.__self__ - -def get_meth_class(obj): - """Return method class""" - if PY2: - # Python 2 - return obj.im_class - else: - # Python 3 - return obj.__self__.__class__ - - -#============================================================================== -# Misc. -#============================================================================== -if PY2: - def _print(*objects, **options): - end = options.get('end', '\n') - file = options.get('file', sys.stdout) - sep = options.get('sep', ' ') - string = sep.join([str(obj) for obj in objects]) - print(string, file=file, end=end, sep=sep) -else: - _print = print - - -if PY2: - # Python 2 - getcwd = os.getcwdu - cmp = cmp - import string - str_lower = string.lower - from itertools import izip_longest as zip_longest - from backports.functools_lru_cache import lru_cache -else: - # Python 3 - getcwd = os.getcwd - def cmp(a, b): - return (a > b) - (a < b) - str_lower = str.lower - from itertools import zip_longest - from functools import lru_cache - -def qbytearray_to_str(qba): - """Convert QByteArray object to str in a way compatible with Python 2/3""" - return str(bytes(qba.toHex().data()).decode()) - -# ============================================================================= -# Dict funcs -# ============================================================================= -if PY3: - def iterkeys(d, **kw): - return iter(d.keys(**kw)) - - def itervalues(d, **kw): - return iter(d.values(**kw)) - - def iteritems(d, **kw): - return iter(d.items(**kw)) - - def iterlists(d, **kw): - return iter(d.lists(**kw)) - - viewkeys = operator.methodcaller("keys") - - viewvalues = operator.methodcaller("values") - - viewitems = operator.methodcaller("items") -else: - def iterkeys(d, **kw): - return d.iterkeys(**kw) - - def itervalues(d, **kw): - return d.itervalues(**kw) - - def iteritems(d, **kw): - return d.iteritems(**kw) - - def iterlists(d, **kw): - return d.iterlists(**kw) - - viewkeys = operator.methodcaller("viewkeys") - - viewvalues = operator.methodcaller("viewvalues") - - viewitems = operator.methodcaller("viewitems") - -# ============================================================================= -# Exceptions -# ============================================================================= -if PY2: - TimeoutError = RuntimeError - FileNotFoundError = IOError -else: - TimeoutError = TimeoutError - FileNotFoundError = FileNotFoundError - -if PY2: - import re - import tokenize - def isidentifier(string): - """Check if string can be a variable name.""" - return re.match(tokenize.Name + r'\Z', string) is not None - - if os.name == 'nt': - def encode(u): - """Try encoding with utf8.""" - if isinstance(u, unicode): - return u.encode('utf8', 'replace') - return u - else: - def encode(u): - """Try encoding with file system encoding.""" - if isinstance(u, unicode): - return u.encode(sys.getfilesystemencoding()) - return u -else: - def isidentifier(string): - """Check if string can be a variable name.""" - return string.isidentifier() - - def encode(u): - """Encoding is not a problem in python 3.""" - return u - - -def compat_exec(code, globals, locals): - # Wrap exec in a function - exec(code, globals, locals) - - -if __name__ == '__main__': - pass diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/dochelpers.py b/external-deps/spyder-kernels/spyder_kernels/utils/dochelpers.py index 19364e89055..d792f063940 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/dochelpers.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/dochelpers.py @@ -10,14 +10,10 @@ from __future__ import print_function +import builtins import inspect import re -# Local imports: -from spyder_kernels.py3compat import (is_text_string, builtins, get_meth_func, - get_meth_class_inst, get_meth_class, - get_func_defaults, to_text_string, PY2) - SYMBOLS = r"[^\'\"a-zA-Z0-9_.]" @@ -57,7 +53,7 @@ def getobjdir(obj): In special cases (e.g. WrapITK package), will return only string elements of result returned by dir(obj) """ - return [item for item in dir(obj) if is_text_string(item)] + return [item for item in dir(obj) if isinstance(item, str)] def getdoc(obj): @@ -84,7 +80,7 @@ def getdoc(obj): # yield anything, either. So assume the most commonly used # multi-byte file encoding (which also covers ascii). try: - docstring = to_text_string(docstring) + docstring = str(docstring) except: pass @@ -101,30 +97,24 @@ def getdoc(obj): doc['docstring'] = docstring return doc if inspect.ismethod(obj): - imclass = get_meth_class(obj) - if get_meth_class_inst(obj) is not None: + imclass = obj.__self__.__class__ + if obj.__self__ is not None: doc['note'] = 'Method of %s instance' \ - % get_meth_class_inst(obj).__class__.__name__ + % obj.__self__.__class__.__name__ else: doc['note'] = 'Unbound %s method' % imclass.__name__ - obj = get_meth_func(obj) + obj = obj.__func__ elif hasattr(obj, '__module__'): doc['note'] = 'Function of %s module' % obj.__module__ else: doc['note'] = 'Function' doc['name'] = obj.__name__ if inspect.isfunction(obj): - if PY2: - args, varargs, varkw, defaults = inspect.getargspec(obj) - doc['argspec'] = inspect.formatargspec( - args, varargs, varkw, defaults, - formatvalue=lambda o:'='+repr(o)) - else: - (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, - annotations) = inspect.getfullargspec(obj) - doc['argspec'] = inspect.formatargspec( - args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, - annotations, formatvalue=lambda o:'='+repr(o)) + (args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, + annotations) = inspect.getfullargspec(obj) + doc['argspec'] = inspect.formatargspec( + args, varargs, varkw, defaults, kwonlyargs, kwonlydefaults, + annotations, formatvalue=lambda o:'='+repr(o)) if name == '': doc['name'] = name + ' lambda ' doc['argspec'] = doc['argspec'][1:-1] # remove parentheses @@ -161,10 +151,10 @@ def getsource(obj): """Wrapper around inspect.getsource""" try: try: - src = to_text_string(inspect.getsource(obj)) + src = str(inspect.getsource(obj)) except TypeError: if hasattr(obj, '__class__'): - src = to_text_string(inspect.getsource(obj.__class__)) + src = str(inspect.getsource(obj.__class__)) else: # Bindings like VTK or ITK require this case src = getdoc(obj) @@ -233,7 +223,7 @@ def getargs(obj): if inspect.isfunction(obj) or inspect.isbuiltin(obj): func_obj = obj elif inspect.ismethod(obj): - func_obj = get_meth_func(obj) + func_obj = obj.__func__ elif inspect.isclass(obj) and hasattr(obj, '__init__'): func_obj = getattr(obj, '__init__') else: @@ -257,7 +247,7 @@ def getargs(obj): if isinstance(arg, list): args[i_arg] = "(%s)" % ", ".join(arg) - defaults = get_func_defaults(func_obj) + defaults = func_obj.__defaults__ if defaults is not None: for index, default in enumerate(defaults): args[index + len(args) - len(defaults)] += '=' + repr(default) @@ -336,7 +326,7 @@ def isdefined(obj, force_import=False, namespace=None): if __name__ == "__main__": - class Test(object): + class Test: def method(self, x, y=2): pass print(getargtxt(Test.__init__)) # spyder: test-skip diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/iofuncs.py b/external-deps/spyder-kernels/spyder_kernels/utils/iofuncs.py index 7565a17b2e3..39b4db07203 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/iofuncs.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/iofuncs.py @@ -29,9 +29,9 @@ import dis import copy import glob +import pickle # Local imports -from spyder_kernels.py3compat import getcwd, pickle, PY2, to_text_string from spyder_kernels.utils.lazymodules import ( FakeObject, numpy as np, pandas as pd, PIL, scipy as sp) @@ -83,7 +83,6 @@ def _is_allowed(self, frame): dis.opmap.get('STOP_CODE', 0)] bytecode = frame.f_code.co_code instruction = bytecode[frame.f_lasti + 3] - instruction = ord(instruction) if PY2 else instruction return instruction in allowed __setattr__ = dict.__setitem__ @@ -254,11 +253,7 @@ def load_pickle(filename): def load_json(filename): """Load a json file as a dictionary""" try: - if PY2: - args = 'rb' - else: - args = 'r' - with open(filename, args) as fid: + with open(filename, 'r') as fid: data = json.load(fid) return data, None except Exception as err: @@ -268,7 +263,7 @@ def load_json(filename): def save_dictionary(data, filename): """Save dictionary in a single file .spydata file""" filename = osp.abspath(filename) - old_cwd = getcwd() + old_cwd = os.getcwd() os.chdir(osp.dirname(filename)) error_message = None skipped_keys = [] @@ -359,7 +354,7 @@ def save_dictionary(data, filename): tar.add(osp.basename(fname)) os.remove(fname) except (RuntimeError, pickle.PicklingError, TypeError) as error: - error_message = to_text_string(error) + error_message = str(error) else: if skipped_keys: skipped_keys.sort() @@ -373,7 +368,7 @@ def save_dictionary(data, filename): def load_dictionary(filename): """Load dictionary from .spydata file""" filename = osp.abspath(filename) - old_cwd = getcwd() + old_cwd = os.getcwd() tmp_folder = tempfile.mkdtemp() os.chdir(tmp_folder) data = None @@ -382,7 +377,7 @@ def load_dictionary(filename): with tarfile.open(filename, "r") as tar: tar.extractall() pickle_filename = glob.glob('*.pickle')[0] - # 'New' format (Spyder >=2.2 for Python 2 and Python 3) + # 'New' format (Spyder >=2.2) with open(pickle_filename, 'rb') as fdesc: data = pickle.loads(fdesc.read()) saved_arrays = {} @@ -402,18 +397,18 @@ def load_dictionary(filename): pass # Except AttributeError from e.g. trying to load function no longer present except (AttributeError, EOFError, ValueError) as error: - error_message = to_text_string(error) + error_message = str(error) # To ensure working dir gets changed back and temp dir wiped no matter what finally: os.chdir(old_cwd) try: shutil.rmtree(tmp_folder) except OSError as error: - error_message = to_text_string(error) + error_message = str(error) return data, error_message -class IOFunctions(object): +class IOFunctions: def __init__(self): self.load_extensions = None self.save_extensions = None @@ -432,7 +427,7 @@ def setup(self): save_filters = [] load_ext = [] for ext, name, loadfunc, savefunc in iofuncs: - filter_str = to_text_string(name + " (*%s)" % ext) + filter_str = str(name + " (*%s)" % ext) if loadfunc is not None: load_filters.append(filter_str) load_extensions[filter_str] = ext @@ -442,9 +437,9 @@ def setup(self): save_extensions[filter_str] = ext save_filters.append(filter_str) save_funcs[ext] = savefunc - load_filters.insert(0, to_text_string("Supported files"+" (*"+\ - " *".join(load_ext)+")")) - load_filters.append(to_text_string("All files (*.*)")) + load_filters.insert(0, str("Supported files"+" (*"+\ + " *".join(load_ext)+")")) + load_filters.append(str("All files (*.*)")) self.load_filters = "\n".join(load_filters) self.save_filters = "\n".join(save_filters) self.load_funcs = load_funcs diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/lazymodules.py b/external-deps/spyder-kernels/spyder_kernels/utils/lazymodules.py index d65847b44b3..75b5b3a94e1 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/lazymodules.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/lazymodules.py @@ -18,12 +18,12 @@ # ============================================================================= # Auxiliary classes # ============================================================================= -class FakeObject(object): +class FakeObject: """Fake class used in replacement of missing objects""" pass -class LazyModule(object): +class LazyModule: """Lazy module loader class.""" def __init__(self, modname, second_level_attrs=None): diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/misc.py b/external-deps/spyder-kernels/spyder_kernels/utils/misc.py index 56ec5f215ec..bbb9b050cac 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/misc.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/misc.py @@ -10,7 +10,7 @@ import re -from spyder_kernels.py3compat import lru_cache +from functools import lru_cache @lru_cache(maxsize=100) diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/nsview.py b/external-deps/spyder-kernels/spyder_kernels/utils/nsview.py index 255ae3f8332..4109827fcb6 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/nsview.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/nsview.py @@ -16,12 +16,6 @@ import inspect import re -# Local imports -from spyder_kernels.py3compat import (NUMERIC_TYPES, INT_TYPES, TEXT_TYPES, - to_text_string, is_text_string, - is_type_text_string, - is_binary_string, PY2, - to_binary_string, iteritems) from spyder_kernels.utils.lazymodules import ( bs4, FakeObject, numpy as np, pandas as pd, PIL) @@ -263,7 +257,7 @@ def default_display(value, with_module=True): return name + ' object of ' + module + ' module' return name except Exception: - type_str = to_text_string(object_type) + type_str = str(object_type) return type_str[1:-1] @@ -274,7 +268,7 @@ def collections_display(value, level): # Get elements if is_dict: - elements = iteritems(value) + elements = iter(value.items()) else: elements = value @@ -362,27 +356,15 @@ def value_to_display(value, minmax=False, level=0): elif isinstance(value, pd.DataFrame): if level == 0: cols = value.columns - if PY2 and len(cols) > 0: - # Get rid of possible BOM utf-8 data present at the - # beginning of a file, which gets attached to the first - # column header when headers are present in the first - # row. - # Fixes Issue 2514 - try: - ini_col = to_text_string(cols[0], encoding='utf-8-sig') - except: - ini_col = to_text_string(cols[0]) - cols = [ini_col] + [to_text_string(c) for c in cols[1:]] - else: - cols = [to_text_string(c) for c in cols] + cols = [str(c) for c in cols] display = 'Column names: ' + ', '.join(list(cols)) else: display = 'Dataframe' elif isinstance(value, bs4.element.NavigableString): # Fixes Issue 2448 - display = to_text_string(value) + display = str(value) if level > 0: - display = u"'" + display + u"'" + display = "'" + display + "'" elif isinstance(value, pd.Index): if level == 0: try: @@ -391,33 +373,34 @@ def value_to_display(value, minmax=False, level=0): display = value.summary() else: display = 'Index' - elif is_binary_string(value): + elif isinstance(value, bytes): # We don't apply this to classes that extend string types # See issue 5636 - if is_type_text_string(value): + if type(value) in [str, bytes]: try: - display = to_text_string(value, 'utf8') + display = str(value, 'utf8') if level > 0: - display = u"'" + display + u"'" + display = "'" + display + "'" except: display = value if level > 0: display = b"'" + display + b"'" else: display = default_display(value) - elif is_text_string(value): + elif isinstance(value, str): # We don't apply this to classes that extend string types # See issue 5636 - if is_type_text_string(value): + if type(value) in [str, bytes]: display = value if level > 0: - display = u"'" + display + u"'" + display = "'" + display + "'" else: display = default_display(value) + elif (isinstance(value, datetime.date) or isinstance(value, datetime.timedelta)): display = str(value) - elif (isinstance(value, NUMERIC_TYPES) or + elif (isinstance(value, (int, float, complex)) or isinstance(value, bool) or isinstance(value, numeric_numpy_types)): display = repr(value) @@ -432,10 +415,10 @@ def value_to_display(value, minmax=False, level=0): # Truncate display at 70 chars to avoid freezing Spyder # because of large displays if len(display) > 70: - if is_binary_string(display): + if isinstance(display, bytes): ellipses = b' ...' else: - ellipses = u' ...' + ellipses = ' ...' display = display[:70].rstrip() + ellipses # Restore Numpy printoptions @@ -448,7 +431,7 @@ def value_to_display(value, minmax=False, level=0): def display_to_value(value, default_value, ignore_errors=True): """Convert back to value""" from qtpy.compat import from_qvariant - value = from_qvariant(value, to_text_string) + value = from_qvariant(value, str) try: np_dtype = get_numpy_dtype(default_value) if isinstance(default_value, bool): @@ -463,10 +446,10 @@ def display_to_value(value, default_value, ignore_errors=True): value = np_dtype(complex(value)) else: value = np_dtype(value) - elif is_binary_string(default_value): - value = to_binary_string(value, 'utf8') - elif is_text_string(default_value): - value = to_text_string(value) + elif isinstance(default_value, bytes): + value = bytes(value, 'utf-8') + elif isinstance(default_value, str): + value = str(value) elif isinstance(default_value, complex): value = complex(value) elif isinstance(default_value, float): @@ -516,7 +499,7 @@ def get_type_string(item): return "Series" found = re.findall(r"<(?:type|class) '(\S*)'>", - to_text_string(type(item))) + str(type(item))) if found: if found[0] == 'type': return 'class' @@ -629,7 +612,7 @@ def get_supported_types(): """ from datetime import date, timedelta editable_types = [int, float, complex, list, set, dict, tuple, date, - timedelta] + list(TEXT_TYPES) + list(INT_TYPES) + timedelta, str] try: from numpy import ndarray, matrix, generic editable_types += [ndarray, matrix, generic] diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_dochelpers.py b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_dochelpers.py index 35b833f8026..8abba539fd9 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_dochelpers.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_dochelpers.py @@ -19,7 +19,6 @@ # Local imports from spyder_kernels.utils.dochelpers import (getargtxt, getdoc, getobj, isdefined) -from spyder_kernels.py3compat import PY2 class Test(object): @@ -27,8 +26,7 @@ def method(self, x, y=2): pass -@pytest.mark.skipif(PY2 or os.name == 'nt', - reason="Only works on Linux and Mac") +@pytest.mark.skipif(os.name == 'nt', reason="Only works on Linux and Mac") def test_dochelpers(): """Test dochelpers.""" assert getargtxt(Test.method) == ['x, ', 'y=2'] diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_iofuncs.py b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_iofuncs.py index 2af9c767a03..eb29241f8e2 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_iofuncs.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_iofuncs.py @@ -21,7 +21,6 @@ # Local imports import spyder_kernels.utils.iofuncs as iofuncs -from spyder_kernels.py3compat import is_text_string # Full path to this file's parent directory for loading data @@ -48,7 +47,7 @@ def are_namespaces_equal(actual, expected): return are_equal -class CustomObj(object): +class CustomObj: """A custom class of objects for testing.""" def __init__(self, data): self.data = None @@ -254,7 +253,7 @@ def test_spydata_import_witherror(): original_cwd = os.getcwd() path = os.path.join(LOCATION, 'export_data_withfunction.spydata') data, error = iofuncs.load_dictionary(path) - assert error and is_text_string(error) + assert error and isinstance(error, str) assert data is None assert os.getcwd() == original_cwd diff --git a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_nsview.py b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_nsview.py index 5a3fbdbdbb3..071616b9854 100644 --- a/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_nsview.py +++ b/external-deps/spyder-kernels/spyder_kernels/utils/tests/test_nsview.py @@ -21,7 +21,6 @@ import PIL.Image # Local imports -from spyder_kernels.py3compat import PY2 from spyder_kernels.utils.nsview import ( sort_against, is_supported, value_to_display, get_size, get_supported_types, get_type_string, get_numpy_type_string, @@ -108,7 +107,7 @@ def test_none_values_are_supported(): def test_str_subclass_display(): - """Test for value_to_display of subclasses of str/basestring.""" + """Test for value_to_display of subclasses of str.""" class Test(str): def __repr__(self): return 'test' @@ -276,12 +275,6 @@ def test_str_in_container_display(): # Assert that both bytes and unicode return the right display assert value_to_display([b'a', u'b']) == "['a', 'b']" - # Encoded unicode gives bytes and it can't be transformed to - # unicode again. So this test the except part of - # is_binary_string(value) in value_to_display - if PY2: - assert value_to_display([u'Э'.encode('cp1251')]) == "['\xdd']" - def test_ellipses(tmpdir): """ @@ -306,11 +299,9 @@ def test_get_type_string(): # Bools assert get_type_string(True) == 'bool' - # Numeric types (PY2 has long, which disappeared in PY3) - if not PY2: - expected = ['int', 'float', 'complex'] - numeric_types = [1, 1.5, 1 + 2j] - assert [get_type_string(t) for t in numeric_types] == expected + expected = ['int', 'float', 'complex'] + numeric_types = [1, 1.5, 1 + 2j] + assert [get_type_string(t) for t in numeric_types] == expected # Lists assert get_type_string([1, 2, 3]) == 'list' @@ -325,8 +316,7 @@ def test_get_type_string(): assert get_type_string((1, 2, 3)) == 'tuple' # Strings - if not PY2: - assert get_type_string('foo') == 'str' + assert get_type_string('foo') == 'str' # Numpy objects assert get_type_string(np.array([1, 2, 3])) == 'NDArray'