Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-spyder-kernels for openSUSE:Factory checked in at 2022-04-11 23:48:48 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-spyder-kernels (Old) and /work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1900 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-spyder-kernels" Mon Apr 11 23:48:48 2022 rev:33 rq:968083 version:2.3.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-spyder-kernels/python-spyder-kernels.changes 2022-01-22 08:19:31.554361259 +0100 +++ /work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1900/python-spyder-kernels.changes 2022-04-11 23:50:17.206356356 +0200 @@ -1,0 +2,24 @@ +Sat Apr 9 22:17:26 UTC 2022 - Ben Greiner <c...@bnavigator.de> + +- Update to version 2.3.0 + * Add new handler to detect the current Matplotlib interactive + backend. + * Increase minimal required version of ipykernel to 6.9.2, by + @ccordoba12 + * Handle getting dasks objects size, by @dalthviz + * Add new handler to detect the current Matplotlib interactive + backend, by @ccordoba12 + * Remove support for outdated and unused Matplotlib backends, by + @ccordoba12 + * Catch FileNotFoundError when trying to get file code from the + frontend, by @ccordoba12 + * Increase minimal required IPython version to 7.31.1, by + @ccordoba12 (344) + * Avoid modifying the namespace view settings by reference, by + @impact27 (320) + * Fix issues when debugging comprehensions, by @impact27 (371) + * Leave unsaved files in linecache, by @impact27 + * Print last line of Pdb code and some debugger fixes, by + @impact27 (330) + +------------------------------------------------------------------- Old: ---- python-spyder-kernels-2.2.1.tar.gz New: ---- python-spyder-kernels-2.3.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-spyder-kernels.spec ++++++ --- /var/tmp/diff_new_pack.PmghOo/_old 2022-04-11 23:50:17.770349922 +0200 +++ /var/tmp/diff_new_pack.PmghOo/_new 2022-04-11 23:50:17.774349875 +0200 @@ -21,7 +21,7 @@ # flaky for obs, only test locally %bcond_with dasktest Name: python-spyder-kernels -Version: 2.2.1 +Version: 2.3.0 Release: 0 Summary: Jupyter kernels for Spyder's console License: MIT @@ -29,6 +29,7 @@ URL: https://github.com/spyder-ide/spyder-kernels # PyPI tarballs do not include the tests: https://github.com/spyder-ide/spyder-kernels/issues/66 Source: %{url}/archive/v%{version}.tar.gz#/%{name}-%{version}.tar.gz +BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module setuptools} BuildRequires: fdupes BuildRequires: python-rpm-macros @@ -37,8 +38,8 @@ BuildRequires: %{python_module Pillow} BuildRequires: %{python_module cloudpickle} BuildRequires: %{python_module flaky} -BuildRequires: %{python_module ipykernel >= 6.6.1} -BuildRequires: %{python_module ipython >= 7.6.0} +BuildRequires: %{python_module ipykernel >= 6.9.2} +BuildRequires: %{python_module ipython >= 7.31.1} BuildRequires: %{python_module jupyter_client >= 7.1.0} BuildRequires: %{python_module matplotlib} BuildRequires: %{python_module numpy} @@ -53,8 +54,8 @@ %endif # /SECTION Requires: python-cloudpickle -Requires: python-ipykernel >= 6.6.1 -Requires: python-ipython >= 7.6.0 +Requires: python-ipykernel >= 6.9.2 +Requires: python-ipython >= 7.31.1 Requires: python-jupyter_client >= 7.1.0 Requires: python-pyzmq >= 22.1 Requires: python-wurlitzer >= 1.0.3 ++++++ python-spyder-kernels-2.2.1.tar.gz -> python-spyder-kernels-2.3.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/.github/workflows/linux-pip-tests.yml new/spyder-kernels-2.3.0/.github/workflows/linux-pip-tests.yml --- old/spyder-kernels-2.2.1/.github/workflows/linux-pip-tests.yml 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/.github/workflows/linux-pip-tests.yml 2022-03-30 04:17:43.000000000 +0200 @@ -22,6 +22,7 @@ fail-fast: false matrix: PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] + timeout-minutes: 20 steps: - name: Checkout branch uses: actions/checkout@v1 @@ -38,7 +39,10 @@ python-version: ${{ matrix.PYTHON_VERSION }} - name: Install package and dependencies shell: bash -l {0} - run: pip install -e .[test] + run: | + pip install -e .[test] + # Zict 2.1.0 is not compatible with Python 3 + pip install zict==2.0.0 - name: Show environment information shell: bash -l {0} run: | diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/.github/workflows/linux-tests.yml new/spyder-kernels-2.3.0/.github/workflows/linux-tests.yml --- old/spyder-kernels-2.2.1/.github/workflows/linux-tests.yml 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/.github/workflows/linux-tests.yml 2022-03-30 04:17:43.000000000 +0200 @@ -18,11 +18,12 @@ CI: True PYTHON_VERSION: ${{ matrix.PYTHON_VERSION }} RUNNER_OS: 'ubuntu' + USE_CONDA: 'true' strategy: fail-fast: false matrix: PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] - timeout-minutes: 10 + timeout-minutes: 20 steps: - name: Checkout branch uses: actions/checkout@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/.github/workflows/macos-tests.yml new/spyder-kernels-2.3.0/.github/workflows/macos-tests.yml --- old/spyder-kernels-2.2.1/.github/workflows/macos-tests.yml 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/.github/workflows/macos-tests.yml 2022-03-30 04:17:43.000000000 +0200 @@ -22,7 +22,7 @@ fail-fast: false matrix: PYTHON_VERSION: ['2.7', '3.7', '3.8', '3.9'] - timeout-minutes: 10 + timeout-minutes: 25 steps: - name: Checkout branch uses: actions/checkout@v1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/CHANGELOG.md new/spyder-kernels-2.3.0/CHANGELOG.md --- old/spyder-kernels-2.2.1/CHANGELOG.md 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/CHANGELOG.md 2022-03-30 04:17:43.000000000 +0200 @@ -1,5 +1,40 @@ # History of changes +## Version 2.3.0 (2022-03-30) + +### New features + +* Add new handler to detect the current Matplotlib interactive backend. +* Print last line of cells and Pdb code. + +### Issues Closed + +* [Issue 371](https://github.com/spyder-ide/spyder-kernels/issues/371) - Can't debug comprehensions ([PR 370](https://github.com/spyder-ide/spyder-kernels/pull/370) by [@impact27](https://github.com/impact27)) +* [Issue 344](https://github.com/spyder-ide/spyder-kernels/issues/344) - Drop support for Python 3.6 by requiring a more recent IPython version ([PR 373](https://github.com/spyder-ide/spyder-kernels/pull/373) by [@ccordoba12](https://github.com/ccordoba12)) +* [Issue 330](https://github.com/spyder-ide/spyder-kernels/issues/330) - spydercustomize in debug stack ([PR 355](https://github.com/spyder-ide/spyder-kernels/pull/355) by [@impact27](https://github.com/impact27)) +* [Issue 320](https://github.com/spyder-ide/spyder-kernels/issues/320) - The length of the "excluded_names" list increases. ([PR 372](https://github.com/spyder-ide/spyder-kernels/pull/372) by [@impact27](https://github.com/impact27)) + +In this release 4 issues were closed. + +### Pull Requests Merged + +* [PR 379](https://github.com/spyder-ide/spyder-kernels/pull/379) - PR: Increase minimal required version of ipykernel to 6.9.2, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 377](https://github.com/spyder-ide/spyder-kernels/pull/377) - PR: Handle getting dasks objects size, by [@dalthviz](https://github.com/dalthviz) +* [PR 376](https://github.com/spyder-ide/spyder-kernels/pull/376) - PR: Add new handler to detect the current Matplotlib interactive backend, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 375](https://github.com/spyder-ide/spyder-kernels/pull/375) - PR: Remove support for outdated and unused Matplotlib backends, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 374](https://github.com/spyder-ide/spyder-kernels/pull/374) - PR: Catch FileNotFoundError when trying to get file code from the frontend, by [@ccordoba12](https://github.com/ccordoba12) +* [PR 373](https://github.com/spyder-ide/spyder-kernels/pull/373) - PR: Increase minimal required IPython version to 7.31.1, by [@ccordoba12](https://github.com/ccordoba12) ([344](https://github.com/spyder-ide/spyder-kernels/issues/344)) +* [PR 372](https://github.com/spyder-ide/spyder-kernels/pull/372) - PR: Avoid modifying the namespace view settings by reference, by [@impact27](https://github.com/impact27) ([320](https://github.com/spyder-ide/spyder-kernels/issues/320)) +* [PR 370](https://github.com/spyder-ide/spyder-kernels/pull/370) - PR: Fix issues when debugging comprehensions, by [@impact27](https://github.com/impact27) ([371](https://github.com/spyder-ide/spyder-kernels/issues/371)) +* [PR 369](https://github.com/spyder-ide/spyder-kernels/pull/369) - PR: Leave unsaved files in linecache, by [@impact27](https://github.com/impact27) +* [PR 355](https://github.com/spyder-ide/spyder-kernels/pull/355) - PR: Print last line of Pdb code and some debugger fixes, by [@impact27](https://github.com/impact27) ([330](https://github.com/spyder-ide/spyder-kernels/issues/330)) + +In this release 10 pull requests were closed. + + +---- + + ## Version 2.2.1 (2022-01-13) ### Issues Closed diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/requirements/posix.txt new/spyder-kernels-2.3.0/requirements/posix.txt --- old/spyder-kernels-2.2.1/requirements/posix.txt 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/requirements/posix.txt 2022-03-30 04:17:43.000000000 +0200 @@ -1,6 +1,6 @@ cloudpickle -ipykernel>=6.6.1 -ipython>=7.6.0,<8 +ipykernel>=6.9.2 +ipython>=7.31.1,<8 jupyter_client>=7.1.0 pyzmq>=22.1.0 wurlitzer>=1.0.3 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/requirements/python-27.txt new/spyder-kernels-2.3.0/requirements/python-27.txt --- old/spyder-kernels-2.2.1/requirements/python-27.txt 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/requirements/python-27.txt 2022-03-30 04:17:43.000000000 +0200 @@ -7,3 +7,5 @@ wurlitzer>=1.0.3 # To avoid an error with conda click =7 +# To avoid a problem with zict +zict <2.1.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/requirements/tests.txt new/spyder-kernels-2.3.0/requirements/tests.txt --- old/spyder-kernels-2.2.1/requirements/tests.txt 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/requirements/tests.txt 2022-03-30 04:17:43.000000000 +0200 @@ -11,5 +11,3 @@ scipy xarray pillow -# Remove when Anaconda updates to a newer ipykernel -ipython_genutils diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/requirements/windows.txt new/spyder-kernels-2.3.0/requirements/windows.txt --- old/spyder-kernels-2.2.1/requirements/windows.txt 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/requirements/windows.txt 2022-03-30 04:17:43.000000000 +0200 @@ -1,7 +1,5 @@ cloudpickle -ipykernel>=6.6.1 -ipython>=7.6.0,<8 +ipykernel>=6.9.2 +ipython>=7.31.1,<8 jupyter_client>=7.1.0 pyzmq>=22.1.0 -# Pin pip version since we are getting 9.x and it causes IPython 6.1.0 to be installed -pip>=19.3.1 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/setup.py new/spyder-kernels-2.3.0/setup.py --- old/spyder-kernels-2.2.1/setup.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/setup.py 2022-03-30 04:17:43.000000000 +0200 @@ -40,9 +40,9 @@ 'backports.functools-lru-cache; python_version<"3"', 'cloudpickle', 'ipykernel<5; python_version<"3"', - 'ipykernel>=6.6.1; python_version>="3"', + 'ipykernel>=6.9.2; python_version>="3"', 'ipython<6; python_version<"3"', - 'ipython>=7.6.0,<8; python_version>="3"', + 'ipython>=7.31.1,<8; python_version>="3"', 'jupyter-client>=5.3.4,<6; python_version<"3"', 'jupyter-client>=7.1.0; python_version>="3"', 'pyzmq>=17,<20; python_version<"3"', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/_version.py new/spyder-kernels-2.3.0/spyder_kernels/_version.py --- old/spyder-kernels-2.2.1/spyder_kernels/_version.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/_version.py 2022-03-30 04:17:43.000000000 +0200 @@ -8,5 +8,5 @@ """Version File.""" -VERSION_INFO = (2, 2, 1) +VERSION_INFO = (2, 3, 0) __version__ = '.'.join(map(str, VERSION_INFO)) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/comms/frontendcomm.py new/spyder-kernels-2.3.0/spyder_kernels/comms/frontendcomm.py --- old/spyder-kernels-2.2.1/spyder_kernels/comms/frontendcomm.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/comms/frontendcomm.py 2022-03-30 04:17:43.000000000 +0200 @@ -34,7 +34,7 @@ return port -def frontend_request(blocking=True, timeout=None): +def frontend_request(blocking, timeout=None): """ Send a request to the frontend. @@ -261,8 +261,11 @@ """Call the callback function for the remote call.""" saved_stdout_write = sys.stdout.write saved_stderr_write = sys.stderr.write - sys.stdout.write = WriteWrapper(saved_stdout_write, call_name) - sys.stderr.write = WriteWrapper(saved_stderr_write, call_name) + thread_id = threading.get_ident() + sys.stdout.write = WriteWrapper( + saved_stdout_write, call_name, thread_id) + sys.stderr.write = WriteWrapper( + saved_stderr_write, call_name, thread_id) try: return super(FrontendComm, self)._remote_callback( call_name, call_args, call_kwargs) @@ -274,9 +277,10 @@ class WriteWrapper(object): """Wrapper to warn user when text is printed.""" - def __init__(self, write, name): + def __init__(self, write, name, thread_id): self._write = write self._name = name + self._thread_id = thread_id self._warning_shown = False def is_benign_message(self, message): @@ -293,6 +297,9 @@ def __call__(self, string): """Print warning once.""" + if self._thread_id != threading.get_ident(): + return self._write(string) + if not self.is_benign_message(string): if not self._warning_shown: self._warning_shown = True diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/console/kernel.py new/spyder-kernels-2.3.0/spyder_kernels/console/kernel.py --- old/spyder-kernels-2.2.1/spyder_kernels/console/kernel.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/console/kernel.py 2022-03-30 04:17:43.000000000 +0200 @@ -12,6 +12,7 @@ # Standard library imports from distutils.version import LooseVersion +import logging import os import sys import threading @@ -22,9 +23,9 @@ from traitlets.config.loader import LazyConfigValue # Local imports -from spyder_kernels.py3compat import TEXT_TYPES, to_text_string -from spyder_kernels.comms.frontendcomm import FrontendComm -from spyder_kernels.py3compat import PY3, input +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 ( MPL_BACKENDS_FROM_SPYDER, MPL_BACKENDS_TO_SPYDER, INLINE_FIGURE_FORMATS) @@ -34,6 +35,10 @@ if PY3: import faulthandler + +logger = logging.getLogger(__name__) + + # Excluded variables from the Variable Explorer (i.e. they are not # shown at all there) EXCLUDED_NAMES = ['In', 'Out', 'exit', 'get_ipython', 'quit'] @@ -78,6 +83,7 @@ 'update_syspath': self.update_syspath, 'is_special_kernel_valid': self.is_special_kernel_valid, 'get_matplotlib_backend': self.get_matplotlib_backend, + 'get_mpl_interactive_backend': self.get_mpl_interactive_backend, 'pdb_input_reply': self.pdb_input_reply, '_interrupt_eventloop': self._interrupt_eventloop, 'enable_faulthandler': self.enable_faulthandler, @@ -88,7 +94,6 @@ call_id, handlers[call_id]) self.namespace_view_settings = {} - self._pdb_step = None self._mpl_backend_error = None self._running_namespace = None self._pdb_input_line = None @@ -301,13 +306,20 @@ return self.shell.pdb_session.do_complete(code, cursor_pos) return self._do_complete(code, cursor_pos) - def publish_pdb_state(self): - """Publish Pdb state.""" - if self.shell.pdb_session: - state = dict(namespace_view = self.get_namespace_view(), - var_properties = self.get_var_properties(), - step = self._pdb_step) + def publish_pdb_state(self, step): + """ + Publish Variable Explorer state and Pdb step through + send_spyder_msg. + """ + state = dict( + namespace_view=self.get_namespace_view(), + var_properties=self.get_var_properties(), + step=step + ) + try: self.frontend_call(blocking=False).pdb_state(state) + except (CommError, TimeoutError): + logger.debug("Could not send Pdb state to the frontend.") def set_spyder_breakpoints(self, breakpoints): """ @@ -437,6 +449,60 @@ except Exception: return None + def get_mpl_interactive_backend(self): + """ + Get current Matplotlib interactive backend. + + This is different from the current backend because, for instance, the + user can set first the Qt5 backend, then the Inline one. In that case, + the current backend is Inline, but the current interactive one is Qt5, + and this backend can't be changed without a kernel restart. + """ + # Mapping from frameworks to backend names. + mapping = { + 'qt': 'QtAgg', # For Matplotlib 3.5+ + 'qt5': 'Qt5Agg', + 'tk': 'TkAgg', + 'macosx': 'MacOSX' + } + + try: + # --- Get interactive framework + framework = None + + # This is necessary because _get_running_interactive_framework + # can't detect Tk in a Jupyter kernel. + if hasattr(self, 'app_wrapper'): + if hasattr(self.app_wrapper, 'app'): + import tkinter + if isinstance(self.app_wrapper.app, tkinter.Tk): + framework = 'tk' + + if framework is None: + try: + # This is necessary for Matplotlib 3.3.0+ + from matplotlib import cbook + framework = cbook._get_running_interactive_framework() + except AttributeError: + # For older versions + from matplotlib import backends + framework = backends._get_running_interactive_framework() + + # --- Return backend according to framework + if framework is None: + # Since no interactive backend has been set yet, this is + # equivalent to having the inline one. + return 0 + elif framework in mapping: + return MPL_BACKENDS_TO_SPYDER[mapping[framework]] + else: + # This covers the case of other backends (e.g. Wx or Gtk) + # which users can set interactively with the %matplotlib + # magic but not through our Preferences. + return -1 + except Exception: + return None + 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)] @@ -702,7 +768,12 @@ """ import traceback from IPython.core.getipython import get_ipython - import matplotlib + + # Don't proceed further if there's any error while importing Matplotlib + try: + import matplotlib + except Exception: + return generic_error = ( "\n" + "="*73 + "\n" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/console/tests/test_console_kernel.py new/spyder-kernels-2.3.0/spyder_kernels/console/tests/test_console_kernel.py --- old/spyder-kernels-2.2.1/spyder_kernels/console/tests/test_console_kernel.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/console/tests/test_console_kernel.py 2022-03-30 04:17:43.000000000 +0200 @@ -33,6 +33,7 @@ # 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 from spyder_kernels.customize.spyderpdb import SpyderPdb @@ -1093,5 +1094,44 @@ pdb_obj.curframe_locals = None +@flaky(max_runs=3) +@pytest.mark.parametrize("backend", [None, 'inline', 'tk', 'qt5']) +@pytest.mark.skipif(PY2, reason="Doesn't work on Python 2") +@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") +def test_get_interactive_backend(backend): + """ + Test that we correctly get the interactive backend set in the kernel. + """ + cmd = "from spyder_kernels.console import start; start.main()" + + with setup_kernel(cmd) as client: + # Set backend + if backend is not None: + client.execute("%matplotlib {}".format(backend)) + client.get_shell_msg(timeout=TIMEOUT) + + # Get backend + code = "backend = get_ipython().kernel.get_mpl_interactive_backend()" + client.execute(code, user_expressions={'output': 'backend'}) + reply = client.get_shell_msg(timeout=TIMEOUT) + while 'user_expressions' not in reply['content']: + reply = client.get_shell_msg(timeout=TIMEOUT) + + # Get value obtained through user_expressions + user_expressions = reply['content']['user_expressions'] + value = user_expressions['output']['data']['text/plain'] + + # Assert we got the right interactive backend + if backend is not None: + assert MPL_BACKENDS_FROM_SPYDER[value] == backend + else: + assert value == '0' + + if __name__ == "__main__": pytest.main() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/customize/namespace_manager.py new/spyder-kernels-2.3.0/spyder_kernels/customize/namespace_manager.py --- old/spyder-kernels-2.2.1/spyder_kernels/customize/namespace_manager.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/customize/namespace_manager.py 2022-03-30 04:17:43.000000000 +0200 @@ -4,8 +4,9 @@ # Licensed under the terms of the MIT License # (see spyder_kernels/__init__.py for details) -import sys import linecache +import os.path +import sys from IPython.core.getipython import get_ipython @@ -21,7 +22,7 @@ """ def __init__(self, filename, namespace=None, current_namespace=False, - file_code=None): + file_code=None, stack_depth=1): self.filename = filename self.ns_globals = namespace self.ns_locals = None @@ -30,6 +31,9 @@ self._previous_main = None self._reset_main = False self._file_code = file_code + ipython_shell = get_ipython() + self.context_globals = ipython_shell.get_global_scope(stack_depth + 1) + self.context_locals = ipython_shell.get_local_scope(stack_depth + 1) def __enter__(self): """ @@ -39,10 +43,8 @@ ipython_shell = get_ipython() if self.ns_globals is None: if self.current_namespace: - # stack_depth = parent of calling function - stack_depth = 2 - self.ns_globals = ipython_shell.get_global_scope(stack_depth) - self.ns_locals = ipython_shell.get_local_scope(stack_depth) + self.ns_globals = self.context_globals + self.ns_locals = self.context_locals if '__file__' in self.ns_globals: self._previous_filename = self.ns_globals['__file__'] self.ns_globals['__file__'] = self.filename @@ -91,17 +93,13 @@ self.ns_globals.pop('__file__') if not self.current_namespace: - # stack_depth = parent of calling function - stack_depth = 2 - ns_globals = ipython_shell.get_global_scope(stack_depth) - ns_locals = ipython_shell.get_local_scope(stack_depth) - ns_globals.update(self.ns_globals) - if ns_locals and self.ns_locals: - ns_locals.update(self.ns_locals) + self.context_globals.update(self.ns_globals) + if self.context_locals and self.ns_locals: + self.context_locals.update(self.ns_locals) if self._previous_main: sys.modules['__main__'] = self._previous_main elif '__main__' in sys.modules and self._reset_main: del sys.modules['__main__'] - if self.filename in linecache.cache: + if self.filename in linecache.cache and os.path.exists(self.filename): linecache.cache.pop(self.filename) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/customize/spydercustomize.py new/spyder-kernels-2.3.0/spyder_kernels/customize/spydercustomize.py --- old/spyder-kernels-2.2.1/spyder_kernels/customize/spydercustomize.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/customize/spydercustomize.py 2022-03-30 04:17:43.000000000 +0200 @@ -11,6 +11,7 @@ # Spyder consoles sitecustomize # +import ast import bdb import cmd import io @@ -27,9 +28,12 @@ from spyder_kernels.comms.frontendcomm import CommError, frontend_request from spyder_kernels.customize.namespace_manager import NamespaceManager -from spyder_kernels.customize.spyderpdb import SpyderPdb, enter_debugger +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 +from spyder_kernels.py3compat import ( + TimeoutError, PY2, _print, encode, compat_exec, FileNotFoundError) +from spyder_kernels.customize.utils import ( + capture_last_Expr, normalise_filename) if not PY2: from IPython.core.inputtransformer2 import ( @@ -377,7 +381,7 @@ def get_current_file_name(): """Get the current file name.""" try: - return frontend_request().current_filename() + 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" @@ -422,7 +426,8 @@ return '\n' * number_empty_lines + code -def exec_code(code, filename, ns_globals, ns_locals=None, post_mortem=False): +def exec_code(code, filename, ns_globals, ns_locals=None, post_mortem=False, + exec_fun=None, capture_last_expression=False): """Execute code and display any exception.""" # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True @@ -432,6 +437,10 @@ filename = encode(filename) code = encode(code) + if exec_fun is None: + # Replace by exec when dropping Python 2 + exec_fun = compat_exec + ipython_shell = get_ipython() is_ipython = os.path.splitext(filename)[1] == '.ipy' try: @@ -439,11 +448,10 @@ # TODO: remove the try-except and let the SyntaxError raise # Because there should not be ipython code in a python file try: - compiled = compile( - transform_cell(code, indent_only=True), filename, 'exec') + ast_code = ast.parse(transform_cell(code, indent_only=True)) except SyntaxError as e: try: - compiled = compile(transform_cell(code), filename, 'exec') + ast_code = ast.parse(transform_cell(code)) except SyntaxError: if PY2: raise e @@ -461,8 +469,23 @@ ".ipy extension.\n") SHOW_INVALID_SYNTAX_MSG = False else: - compiled = compile(transform_cell(code), filename, 'exec') - exec(compiled, ns_globals, ns_locals) + ast_code = ast.parse(transform_cell(code)) + + if code.rstrip()[-1] == ";": + # Supress output with ; + capture_last_expression = False + + if capture_last_expression: + ast_code, capture_last_expression = capture_last_Expr( + ast_code, "_spyder_out") + + exec_fun(compile(ast_code, filename, 'exec'), ns_globals, ns_locals) + + if capture_last_expression: + out = ns_globals.pop("_spyder_out", None) + if out is not None: + return out + except SystemExit as status: # ignore exit(0) if status.code: @@ -478,16 +501,17 @@ else: # We ignore the call to exec ipython_shell.showtraceback(tb_offset=1) - __tracebackhide__ = "__pdb_exit__" + finally: + __tracebackhide__ = "__pdb_exit__" def get_file_code(filename, save_all=True): """Retrive the content of a file.""" # Get code from spyder try: - file_code = frontend_request().get_file_code( + file_code = frontend_request(blocking=True).get_file_code( filename, save_all=save_all) - except (CommError, TimeoutError, RuntimeError): + except (CommError, TimeoutError, RuntimeError, FileNotFoundError): file_code = None if file_code is None: with open(filename, 'r') as f: @@ -505,6 +529,14 @@ post_mortem: boolean, whether to enter post-mortem mode on error current_namespace: if true, run the file in the current namespace """ + return _exec_file( + filename, args, wdir, namespace, + post_mortem, current_namespace, stack_depth=1) + + +def _exec_file(filename=None, args=None, wdir=None, namespace=None, + post_mortem=False, current_namespace=False, stack_depth=0, + exec_fun=None): # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True ipython_shell = get_ipython() @@ -543,8 +575,13 @@ _print("Could not get code from editor.\n") return + # Normalise the filename + filename = os.path.abspath(filename) + filename = os.path.normcase(filename) + with NamespaceManager(filename, namespace, current_namespace, - file_code=file_code) as (ns_globals, ns_locals): + file_code=file_code, stack_depth=stack_depth + 1 + ) as (ns_globals, ns_locals): sys.argv = [filename] if args is not None: for arg in shlex.split(args): @@ -577,15 +614,17 @@ else: _print("Working directory {} doesn't exist.\n".format(wdir)) - if __umr__.has_cython: - # Cython files - with io.open(filename, encoding='utf-8') as f: - ipython_shell.run_cell_magic('cython', '', f.read()) - else: - exec_code(file_code, filename, ns_globals, ns_locals, - post_mortem=post_mortem) - - sys.argv = [''] + try: + if __umr__.has_cython: + # Cython files + with io.open(filename, encoding='utf-8') as f: + ipython_shell.run_cell_magic('cython', '', f.read()) + else: + exec_code(file_code, filename, ns_globals, ns_locals, + post_mortem=post_mortem, exec_fun=exec_fun, + capture_last_expression=False) + finally: + sys.argv = [''] # IPykernel 6.3.0+ shadows our runfile because it depends on the Pydev @@ -612,11 +651,27 @@ if filename is None: return - enter_debugger( - filename, True, - "runfile({}" + - ", args=%r, wdir=%r, current_namespace=%r)" % ( - args, wdir, current_namespace)) + shell = get_ipython() + if shell.is_debugging(): + # Recursive + code = ( + "runfile({}".format(repr(normalise_filename(filename))) + + ", args=%r, wdir=%r, current_namespace=%r)" % ( + args, wdir, current_namespace) + ) + + shell.pdb_session.enter_recursive_debugger( + code, filename, True, + ) + else: + debugger = get_new_debugger(filename, True) + _exec_file( + filename=debugger.canonic(filename), + args=args, wdir=wdir, + current_namespace=current_namespace, + exec_fun=debugger.run, + stack_depth=1 + ) builtins.debugfile = debugfile @@ -626,16 +681,24 @@ """ Run a code cell from an editor as a file. - Currently looks for code in an `ipython` property called `cell_code`. - This property must be set by the editor prior to calling this function. - This function deletes the contents of `cell_code` upon completion. - Parameters ---------- cellname : str or int Cell name or index. filename : str Needed to allow for proper traceback links. + post_mortem: bool + Automatically enter post mortem on exception. + """ + # Tell IPython to hide this frame (>7.16) + __tracebackhide__ = True + return _exec_cell(cellname, filename, post_mortem, stack_depth=1) + + +def _exec_cell(cellname, filename=None, post_mortem=False, stack_depth=0, + exec_fun=None): + """ + Execute a code cell with a given exec function. """ # Tell IPython to hide this frame (>7.16) __tracebackhide__ = True @@ -657,7 +720,8 @@ ipython_shell = get_ipython() try: # Get code from spyder - cell_code = frontend_request().run_cell(cellname, filename) + 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" @@ -676,10 +740,17 @@ file_code = get_file_code(filename, save_all=False) except Exception: file_code = None + + # Normalise the filename + filename = os.path.abspath(filename) + filename = os.path.normcase(filename) + with NamespaceManager(filename, current_namespace=True, - file_code=file_code) as (ns_globals, ns_locals): - exec_code(cell_code, filename, ns_globals, ns_locals, - post_mortem=post_mortem) + file_code=file_code, stack_depth=stack_depth + 1 + ) as (ns_globals, ns_locals): + return exec_code(cell_code, filename, ns_globals, ns_locals, + post_mortem=post_mortem, exec_fun=exec_fun, + capture_last_expression=True) builtins.runcell = runcell @@ -694,10 +765,24 @@ if filename is None: return - enter_debugger( - filename, False, - "runcell({}, ".format(repr(cellname)) + - "{})") + shell = get_ipython() + if shell.is_debugging(): + # Recursive + code = ( + "runcell({}, ".format(repr(cellname)) + + "{})".format(repr(normalise_filename(filename))) + ) + shell.pdb_session.enter_recursive_debugger( + code, filename, False, + ) + else: + debugger = get_new_debugger(filename, False) + _exec_cell( + cellname=cellname, + filename=debugger.canonic(filename), + exec_fun=debugger.run, + stack_depth=1 + ) builtins.debugcell = debugcell @@ -718,7 +803,7 @@ raise RuntimeError('Could not get cell count from frontend.') try: # Get code from spyder - cell_count = frontend_request().cell_count(filename) + cell_count = frontend_request(blocking=True).cell_count(filename) return cell_count except Exception: etype, error, tb = sys.exc_info() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/customize/spyderpdb.py new/spyder-kernels-2.3.0/spyder_kernels/customize/spyderpdb.py --- old/spyder-kernels-2.2.1/spyder_kernels/customize/spyderpdb.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/customize/spyderpdb.py 2022-03-30 04:17:43.000000000 +0200 @@ -19,7 +19,7 @@ from IPython.core.getipython import get_ipython from spyder_kernels.comms.frontendcomm import CommError, frontend_request -from spyder_kernels.customize.utils import path_is_library +from spyder_kernels.customize.utils import path_is_library, capture_last_Expr from spyder_kernels.py3compat import TimeoutError, PY2, _print, isidentifier if not PY2: @@ -175,6 +175,15 @@ if execute_events: get_ipython().events.trigger('pre_execute') + code_ast = ast.parse(line) + + if line.rstrip()[-1] == ";": + # Supress output with ; + capture_last_expression = False + else: + code_ast, capture_last_expression = capture_last_Expr( + code_ast, "_spyderpdb_out") + if locals is not globals: # Mitigates a behaviour of CPython that makes it difficult # to work with exec and the local namespace @@ -195,46 +204,57 @@ # a copy of the curframe locals. This means that closures # for example are early binding instead of late binding. - # Check if line is an expression to print - print_ret = False - try: - code = ast.parse(line + '\n', '<stdin>', 'single') - if len(code.body) == 1: - print_ret = isinstance(code.body[0], ast.Expr) - except SyntaxError: - pass - - # Create a function and load the locals - globals["_spyderpdb_locals"] = locals + # Create a function indent = " " code = ["def _spyderpdb_code():"] + + # Load the locals + globals["_spyderpdb_builtins_locals"] = builtins.locals + + # Save builtins locals in case it is shadowed + globals["_spyderpdb_locals"] = locals + + # 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] + k=k) for k in locals if isidentifier(k)] - # Run the code - if print_ret: - code += [indent + 'print(' + line.strip() + ")"] - else: - code += [indent + l for l in line.splitlines()] # Update the locals - code += [indent + "_spyderpdb_locals.update(locals())"] + code += [indent + "_spyderpdb_locals.update(" + "_spyderpdb_builtins_locals())"] # Run the function code += ["_spyderpdb_code()"] - code = compile('\n'.join(code) + '\n', '<stdin>', 'exec') - try: - exec(code, globals) - finally: - globals.pop("_spyderpdb_locals", None) - globals.pop("_spyderpdb_code", None) - else: - try: - code = compile(line + '\n', '<stdin>', 'single') - except SyntaxError: - # Support multiline statments - code = compile(line + '\n', '<stdin>', 'exec') - exec(code, globals) + + # Cleanup + code += [ + "del _spyderpdb_code", + "del _spyderpdb_locals", + "del _spyderpdb_builtins_locals" + ] + + # Parse the function + fun_ast = ast.parse('\n'.join(code) + '\n') + + # Inject code_ast in the function before the locals update + fun_ast.body[0].body = ( + fun_ast.body[0].body[:-1] # The locals + + code_ast.body # Code to run + + fun_ast.body[0].body[-1:] # Locals update + ) + code_ast = fun_ast + + exec(compile(code_ast, "<stdin>", "exec"), globals) + + if capture_last_expression: + out = globals.pop("_spyderpdb_out", None) + if out is not None: + sys.stdout.flush() + sys.stderr.flush() + frontend_request(blocking=False).show_pdb_output( + repr(out)) + finally: if execute_events: get_ipython().events.trigger('post_execute') @@ -329,7 +349,7 @@ Take a number as argument as an (optional) number of context line to print""" super(SpyderPdb, self).do_where(arg) - frontend_request().do_where() + frontend_request(blocking=False).do_where() do_w = do_where @@ -525,7 +545,7 @@ def preloop(self): """Ask Spyder for breakpoints before the first prompt is created.""" try: - pdb_settings = frontend_request().get_pdb_settings() + pdb_settings = frontend_request(blocking=True).get_pdb_settings() self.pdb_ignore_lib = pdb_settings['pdb_ignore_lib'] self.pdb_execute_events = pdb_settings['pdb_execute_events'] self.pdb_use_exclamation_mark = pdb_settings[ @@ -626,7 +646,7 @@ """ Notify spyder on any pdb command. """ - self.notify_spyder(self.curframe) + self.notify_spyder() return super(SpyderPdb, self).postcmd(stop, line) if PY2: @@ -723,16 +743,13 @@ logger.debug( "Could not send a Pdb continue call to the frontend.") - def notify_spyder(self, frame=None): + def notify_spyder(self): """Send kernel state to the frontend.""" - if frame is None: - frame = self.curframe + frame = self.curframe if frame is None: return - kernel = get_ipython().kernel - # Get filename and line number of the current frame fname = self.canonic(frame.f_code.co_filename) if PY2: @@ -747,13 +764,7 @@ if isinstance(fname, basestring) and isinstance(lineno, int): step = dict(fname=fname, lineno=lineno) - # Publish Pdb state so we can update the Variable Explorer - # and the Editor on the Spyder side - kernel._pdb_step = step - try: - kernel.publish_pdb_state() - except (CommError, TimeoutError): - logger.debug("Could not send Pdb state to the frontend.") + get_ipython().kernel.publish_pdb_state(step) def run(self, cmd, globals=None, locals=None): """Debug a statement executed via the exec() function. @@ -782,43 +793,42 @@ with DebugWrapper(self): super(SpyderPdb, self).runcall(*args, **kwds) - -def enter_debugger(filename, continue_if_has_breakpoints, code_format): - """Enter debugger. Code format should be a format that accept filename.""" - shell = get_ipython() - recursive = shell.is_debugging() - if recursive: - parent_debugger = shell.pdb_session + def enter_recursive_debugger(self, code, filename, + continue_if_has_breakpoints): + """ + Enter debugger recursively. + """ sys.settrace(None) - globals = parent_debugger.curframe.f_globals - locals = parent_debugger.curframe_locals + globals = self.curframe.f_globals + locals = self.curframe_locals # Create child debugger debugger = SpyderPdb( - completekey=parent_debugger.completekey, - stdin=parent_debugger.stdin, stdout=parent_debugger.stdout) - debugger.use_rawinput = parent_debugger.use_rawinput - debugger.prompt = "(%s) " % parent_debugger.prompt.strip() - else: - debugger = SpyderPdb() + completekey=self.completekey, + stdin=self.stdin, stdout=self.stdout) + debugger.use_rawinput = self.use_rawinput + debugger.prompt = "(%s) " % self.prompt.strip() + + filename = debugger.canonic(filename) + debugger._wait_for_mainpyfile = True + debugger.mainpyfile = filename + debugger.continue_if_has_breakpoints = continue_if_has_breakpoints + debugger._user_requested_quit = False + + # Enter recursive debugger + sys.call_tracing(debugger.run, (code, globals, locals)) + # Reset parent debugger + sys.settrace(self.trace_dispatch) + self.lastcmd = debugger.lastcmd + get_ipython().pdb_session = self + + +def get_new_debugger(filename, continue_if_has_breakpoints): + """Get a new debugger.""" + debugger = SpyderPdb() filename = debugger.canonic(filename) debugger._wait_for_mainpyfile = True debugger.mainpyfile = filename debugger.continue_if_has_breakpoints = continue_if_has_breakpoints debugger._user_requested_quit = False - - if os.name == 'nt': - filename = filename.replace('\\', '/') - - code = code_format.format(repr(filename)) - - if recursive: - # Enter recursive debugger - sys.call_tracing(debugger.run, (code, globals, locals)) - # Reset parent debugger - sys.settrace(parent_debugger.trace_dispatch) - parent_debugger.lastcmd = debugger.lastcmd - shell.pdb_session = parent_debugger - else: - # The breakpoint might not be in the cell - debugger.run(code) + return debugger diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/customize/utils.py new/spyder-kernels-2.3.0/spyder_kernels/customize/utils.py --- old/spyder-kernels-2.2.1/spyder_kernels/customize/utils.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/customize/utils.py 2022-03-30 04:17:43.000000000 +0200 @@ -5,6 +5,7 @@ """Utility functions.""" +import ast import os import re import sysconfig @@ -92,3 +93,33 @@ return False else: return False + + +def capture_last_Expr(code_ast, out_varname): + """Parse line and modify code to capture in globals the last expression.""" + # Modify ast code to capture the last expression + capture_last_expression = False + if ( + len(code_ast.body) + and isinstance(code_ast.body[-1], ast.Expr) + ): + capture_last_expression = True + expr_node = code_ast.body[-1] + # Create new assign node + assign_node = ast.parse( + 'globals()[{}] = None'.format(repr(out_varname))).body[0] + # Replace None by the value + assign_node.value = expr_node.value + # Fix line number and column offset + assign_node.lineno = expr_node.lineno + assign_node.col_offset = expr_node.col_offset + code_ast.body[-1] = assign_node + return code_ast, capture_last_expression + + +def normalise_filename(filename): + """Normalise path for window.""" + # Recursive + if os.name == 'nt': + return filename.replace('\\', '/') + return filename diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/py3compat.py new/spyder-kernels-2.3.0/spyder_kernels/py3compat.py --- old/spyder-kernels-2.2.1/spyder_kernels/py3compat.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/py3compat.py 2022-03-30 04:17:43.000000000 +0200 @@ -317,8 +317,10 @@ # ============================================================================= if PY2: TimeoutError = RuntimeError + FileNotFoundError = IOError else: TimeoutError = TimeoutError + FileNotFoundError = FileNotFoundError if PY2: import re @@ -348,5 +350,11 @@ """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 -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/utils/mpl.py new/spyder-kernels-2.3.0/spyder_kernels/utils/mpl.py --- old/spyder-kernels-2.2.1/spyder_kernels/utils/mpl.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/utils/mpl.py 2022-03-30 04:17:43.000000000 +0200 @@ -29,12 +29,9 @@ MPL_BACKENDS_TO_SPYDER = { inline_backend: 0, 'Qt5Agg': 2, - 'Qt4Agg': 3, + 'QtAgg': 2, # For Matplotlib 3.5+ + 'TkAgg': 3, 'MacOSX': 4, - 'GTK3Agg': 5, - 'GTKAgg': 6, - 'WX': 7, - 'TkAgg': 8 } @@ -42,8 +39,6 @@ """Get Matplolib automatic backend option.""" if is_module_installed('PyQt5'): auto_backend = 'qt5' - elif is_module_installed('PyQt4'): - auto_backend = 'qt4' elif is_module_installed('_tkinter'): auto_backend = 'tk' else: @@ -56,10 +51,6 @@ '0': 'inline', '1': automatic_backend(), '2': 'qt5', - '3': 'qt4', - '4': 'osx', - '5': 'gtk3', - '6': 'gtk', - '7': 'wx', - '8': 'tk' + '3': 'tk', + '4': 'osx' } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/spyder-kernels-2.2.1/spyder_kernels/utils/nsview.py new/spyder-kernels-2.3.0/spyder_kernels/utils/nsview.py --- old/spyder-kernels-2.2.1/spyder_kernels/utils/nsview.py 2022-01-13 16:55:24.000000000 +0100 +++ new/spyder-kernels-2.3.0/spyder_kernels/utils/nsview.py 2022-03-30 04:17:43.000000000 +0200 @@ -85,8 +85,19 @@ def get_size(item): """Return shape/size/len of an item of arbitrary type""" try: - if (hasattr(item, 'shape') and - isinstance(item.shape, (tuple, np.integer))): + if ( + hasattr(item, 'size') and hasattr(item.size, 'compute') or + hasattr(item, 'shape') and hasattr(item.shape, 'compute') + ): + # This is necessary to avoid an error when trying to + # get the size/shape of dask objects. We don't compute the + # size/shape since such operation could be expensive. + # Fixes spyder-ide/spyder#16844 + return 1 + elif ( + hasattr(item, 'shape') and + isinstance(item.shape, (tuple, np.integer)) + ): try: if item.shape: # This is needed since values could return as @@ -648,7 +659,7 @@ """ supported_types = get_supported_types() assert mode in list(supported_types.keys()) - excluded_names = settings['excluded_names'] + excluded_names = list(settings['excluded_names']) if more_excluded_names is not None: excluded_names += more_excluded_names return globalsfilter(