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 <[email protected]>
+
+- 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)
[email protected]("backend", [None, 'inline', 'tk', 'qt5'])
[email protected](PY2, reason="Doesn't work on Python 2")
[email protected](
+ not sys.platform.startswith('linux'),
+ reason="Doesn't work reliably on Windows and Mac")
[email protected](
+ 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(