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-07-26 19:45:02
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-spyder-kernels (Old)
 and      /work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1533 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-spyder-kernels"

Tue Jul 26 19:45:02 2022 rev:35 rq:991040 version:2.3.2

Changes:
--------
--- 
/work/SRC/openSUSE:Factory/python-spyder-kernels/python-spyder-kernels.changes  
    2022-05-31 15:47:55.548009871 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-spyder-kernels.new.1533/python-spyder-kernels.changes
    2022-07-26 19:45:04.549765431 +0200
@@ -1,0 +2,21 @@
+Mon Jul 25 12:31:50 UTC 2022 - Ben Greiner <c...@bnavigator.de>
+
+- Update to version 2.3.2
+  * Fixed issue 394 - The variable explorer is broken while
+   debugging
+  * PR 399: Increase minimal required version of jupyter_client to
+    7.3.4, by @ccordoba12
+  * PR 398: Fix module namespace, by @impact27
+  * PR 395: Fix running namespace and improve eventloop integration
+    while debugging, by @impact27 (394)
+  * PR 389: Fix debug filename path for remote debugging, by
+    @impact27 (18330)
+  * PR 388: Fix getting args from functions or methods, by
+    @ccordoba12
+  * PR 386: Fix flaky test, by @impact27
+  * PR 381: Eliminate unnecessary updates of the Variable Explorer
+    while debugging, by @rear1019
+  * PR 378: Append paths that come from Spyder's Python path
+    manager to the end of sys.path, by @mrclary
+
+-------------------------------------------------------------------

Old:
----
  python-spyder-kernels-2.3.1.tar.gz

New:
----
  python-spyder-kernels-2.3.2.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-spyder-kernels.spec ++++++
--- /var/tmp/diff_new_pack.MzBuxs/_old  2022-07-26 19:45:05.017693125 +0200
+++ /var/tmp/diff_new_pack.MzBuxs/_new  2022-07-26 19:45:05.021692507 +0200
@@ -21,7 +21,7 @@
 # flaky for obs, only test locally
 %bcond_with dasktest
 Name:           python-spyder-kernels
-Version:        2.3.1
+Version:        2.3.2
 Release:        0
 Summary:        Jupyter kernels for Spyder's console
 License:        MIT
@@ -29,7 +29,6 @@
 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
@@ -40,7 +39,7 @@
 BuildRequires:  %{python_module flaky}
 BuildRequires:  %{python_module ipykernel >= 6.9.2 with %python-ipykernel < 7}
 BuildRequires:  %{python_module ipython >= 7.31.1}
-BuildRequires:  %{python_module jupyter_client >= 7.3.1 with 
%python-jupyter_client < 8}
+BuildRequires:  %{python_module jupyter_client >= 7.3.4 with 
%python-jupyter_client < 8}
 BuildRequires:  %{python_module matplotlib}
 BuildRequires:  %{python_module numpy}
 BuildRequires:  %{python_module pandas}
@@ -58,7 +57,7 @@
 Requires:       python-pyzmq >= 22.1
 Requires:       python-wurlitzer >= 1.0.3
 Requires:       (python-ipykernel >= 6.9.2 with python-ipykernel < 7)
-Requires:       (python-jupyter_client >= 7.3.1 with python-jupyter_client < 8)
+Requires:       (python-jupyter_client >= 7.3.4 with python-jupyter_client < 8)
 BuildArch:      noarch
 
 %python_subpackages

++++++ python-spyder-kernels-2.3.1.tar.gz -> python-spyder-kernels-2.3.2.tar.gz 
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spyder-kernels-2.3.1/CHANGELOG.md 
new/spyder-kernels-2.3.2/CHANGELOG.md
--- old/spyder-kernels-2.3.1/CHANGELOG.md       2022-05-21 18:36:00.000000000 
+0200
+++ new/spyder-kernels-2.3.2/CHANGELOG.md       2022-07-06 18:22:03.000000000 
+0200
@@ -1,5 +1,30 @@
 # History of changes
 
+## Version 2.3.2 (2022-07-06)
+
+### Issues Closed
+
+* [Issue 394](https://github.com/spyder-ide/spyder-kernels/issues/394) - The 
variable explorer is broken while debugging ([PR 
395](https://github.com/spyder-ide/spyder-kernels/pull/395) by 
[@impact27](https://github.com/impact27))
+
+In this release 1 issue was closed.
+
+### Pull Requests Merged
+
+* [PR 399](https://github.com/spyder-ide/spyder-kernels/pull/399) - PR: 
Increase minimal required version of jupyter_client to 7.3.4, by 
[@ccordoba12](https://github.com/ccordoba12)
+* [PR 398](https://github.com/spyder-ide/spyder-kernels/pull/398) - PR: Fix 
module namespace, by [@impact27](https://github.com/impact27)
+* [PR 395](https://github.com/spyder-ide/spyder-kernels/pull/395) - PR: Fix 
running namespace and improve eventloop integration while debugging, by 
[@impact27](https://github.com/impact27) 
([394](https://github.com/spyder-ide/spyder-kernels/issues/394))
+* [PR 389](https://github.com/spyder-ide/spyder-kernels/pull/389) - PR: Fix 
debug filename path for remote debugging, by 
[@impact27](https://github.com/impact27) 
([18330](https://github.com/spyder-ide/spyder/issues/18330))
+* [PR 388](https://github.com/spyder-ide/spyder-kernels/pull/388) - PR: Fix 
getting args from functions or methods, by 
[@ccordoba12](https://github.com/ccordoba12)
+* [PR 386](https://github.com/spyder-ide/spyder-kernels/pull/386) - PR: Fix 
flaky test, by [@impact27](https://github.com/impact27)
+* [PR 381](https://github.com/spyder-ide/spyder-kernels/pull/381) - PR: 
Eliminate unnecessary updates of the Variable Explorer while debugging, by 
[@rear1019](https://github.com/rear1019)
+* [PR 378](https://github.com/spyder-ide/spyder-kernels/pull/378) - PR: Append 
paths that come from Spyder's Python path manager to the end of `sys.path`, by 
[@mrclary](https://github.com/mrclary)
+
+In this release 8 pull requests were closed.
+
+
+----
+
+
 ## Version 2.3.1 (2022-05-21)
 
 ### Pull Requests Merged
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spyder-kernels-2.3.1/requirements/posix.txt 
new/spyder-kernels-2.3.2/requirements/posix.txt
--- old/spyder-kernels-2.3.1/requirements/posix.txt     2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/requirements/posix.txt     2022-07-06 
18:22:03.000000000 +0200
@@ -1,6 +1,6 @@
 cloudpickle
 ipykernel>=6.9.2,<7
 ipython>=7.31.1,<8
-jupyter_client>=7.3.1,<8
+jupyter_client>=7.3.4,<8
 pyzmq>=22.1.0
 wurlitzer>=1.0.3
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spyder-kernels-2.3.1/requirements/windows.txt 
new/spyder-kernels-2.3.2/requirements/windows.txt
--- old/spyder-kernels-2.3.1/requirements/windows.txt   2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/requirements/windows.txt   2022-07-06 
18:22:03.000000000 +0200
@@ -1,5 +1,5 @@
 cloudpickle
 ipykernel>=6.9.2,<7
 ipython>=7.31.1,<8
-jupyter_client>=7.3.1,<8
+jupyter_client>=7.3.4,<8
 pyzmq>=22.1.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spyder-kernels-2.3.1/setup.py 
new/spyder-kernels-2.3.2/setup.py
--- old/spyder-kernels-2.3.1/setup.py   2022-05-21 18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/setup.py   2022-07-06 18:22:03.000000000 +0200
@@ -44,7 +44,7 @@
     '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"',
+    'jupyter-client>=7.3.4,<8; python_version>="3"',
     'pyzmq>=17,<20; python_version<"3"',
     'pyzmq>=22.1.0; python_version>="3"',
     'wurlitzer>=1.0.3;platform_system!="Windows"',
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/spyder-kernels-2.3.1/spyder_kernels/_version.py 
new/spyder-kernels-2.3.2/spyder_kernels/_version.py
--- old/spyder-kernels-2.3.1/spyder_kernels/_version.py 2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/_version.py 2022-07-06 
18:22:03.000000000 +0200
@@ -8,5 +8,5 @@
 
 """Version File."""
 
-VERSION_INFO = (2, 3, 1)
+VERSION_INFO = (2, 3, 2)
 __version__ = '.'.join(map(str, VERSION_INFO))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/console/kernel.py 
new/spyder-kernels-2.3.2/spyder_kernels/console/kernel.py
--- old/spyder-kernels-2.3.1/spyder_kernels/console/kernel.py   2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/console/kernel.py   2022-07-06 
18:22:03.000000000 +0200
@@ -24,8 +24,8 @@
 
 # Local imports
 from spyder_kernels.py3compat import (
-    TEXT_TYPES, to_text_string, PY3, input, TimeoutError)
-from spyder_kernels.comms.frontendcomm import FrontendComm, CommError
+    TEXT_TYPES, to_text_string, PY3)
+from spyder_kernels.comms.frontendcomm import FrontendComm
 from spyder_kernels.utils.iofuncs import iofunctions
 from spyder_kernels.utils.mpl import (
     MPL_BACKENDS_FROM_SPYDER, MPL_BACKENDS_TO_SPYDER, INLINE_FIGURE_FORMATS)
@@ -96,7 +96,6 @@
         self.namespace_view_settings = {}
         self._mpl_backend_error = None
         self._running_namespace = None
-        self._pdb_input_line = None
         self.faulthandler_handle = None
 
     # -- Public API -----------------------------------------------------------
@@ -306,21 +305,6 @@
             return self.shell.pdb_session.do_complete(code, cursor_pos)
         return self._do_complete(code, cursor_pos)
 
-    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):
         """
         Handle a message from the frontend
@@ -352,10 +336,10 @@
 
     def pdb_input_reply(self, line, echo_stack_entry=True):
         """Get a pdb command from the frontend."""
-        if self.shell.pdb_session:
-            self.shell.pdb_session._disable_next_stack_entry = (
-                not echo_stack_entry)
-        self._pdb_input_line = line
+        debugger = self.shell.pdb_session
+        if debugger:
+            debugger._disable_next_stack_entry = not echo_stack_entry
+            debugger._cmd_input_line = line
         if self.eventloop:
             # Interrupting the eventloop is only implemented when a message is
             # received on the shell channel, but this message is queued and
@@ -365,47 +349,6 @@
             # stop the eventloop. This will call back `_interrupt_eventloop`.
             self.frontend_call().request_interrupt_eventloop()
 
-    def cmd_input(self, prompt=''):
-        """
-        Special input function for commands.
-        Runs the eventloop while debugging.
-        """
-        # Only works if the comm is open and this is a pdb prompt.
-        if not self.frontend_comm.is_open() or not self.shell.is_debugging():
-            return input(prompt)
-
-        # Flush output before making the request.
-        sys.stderr.flush()
-        sys.stdout.flush()
-
-        # Send the input request.
-        self._pdb_input_line = None
-        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)
-
-        # Get input by running eventloop
-        if is_main_thread and self.eventloop:
-            while self._pdb_input_line is None:
-                eventloop = self.eventloop
-                if eventloop:
-                    eventloop(self)
-                else:
-                    break
-
-        # Get input by blocking
-        if self._pdb_input_line is None:
-            self.frontend_comm.wait_until(
-                lambda: self._pdb_input_line is not None)
-
-        return self._pdb_input_line
-
     def _interrupt_eventloop(self):
         """Interrupts the eventloop."""
         # Receiving the request is enough to stop the eventloop.
@@ -634,11 +577,12 @@
                 sys.path.remove(path)
 
         # Add new paths
-        # We do this in reverse order as we use `sys.path.insert(1, path)`.
-        # This ensures the end result has the correct path order.
-        for path, active in reversed(new_path_dict.items()):
-            if active:
-                sys.path.insert(1, path)
+        pypath = [path for path, active in new_path_dict.items() if active]
+        if pypath:
+            sys.path.extend(pypath)
+            os.environ.update({'PYTHONPATH': os.pathsep.join(pypath)})
+        else:
+            os.environ.pop('PYTHONPATH', None)
 
     # -- Private API ---------------------------------------------------
     # --- For the Variable Explorer
@@ -650,17 +594,21 @@
         both locals() and globals() for current frame when debugging
         """
         ns = {}
-        if self._running_namespace is None:
+        if self.shell.is_debugging() and self.shell.pdb_session.prompt_waiting:
+            # Stopped at a pdb prompt
             ns.update(self.shell.user_ns)
+            ns.update(self.shell._pdb_locals)
         else:
-            # This is true when a file is executing.
-            running_globals, running_locals = self._running_namespace
-            ns.update(running_globals)
-            if running_locals is not None:
-                ns.update(running_locals)
+            # Give access to the running namespace if there is one
+            if self._running_namespace is None:
+                ns.update(self.shell.user_ns)
+            else:
+                # This is true when a file is executing.
+                running_globals, running_locals = self._running_namespace
+                ns.update(running_globals)
+                if running_locals is not None:
+                    ns.update(running_locals)
 
-        # Add debugging locals
-        ns.update(self.shell._pdb_locals)
         # Add magics to ns so we can show help about them on the Help
         # plugin
         if with_magics:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/console/tests/test_console_kernel.py 
new/spyder-kernels-2.3.2/spyder_kernels/console/tests/test_console_kernel.py
--- 
old/spyder-kernels-2.3.1/spyder_kernels/console/tests/test_console_kernel.py    
    2022-05-21 18:36:00.000000000 +0200
+++ 
new/spyder-kernels-2.3.2/spyder_kernels/console/tests/test_console_kernel.py    
    2022-07-06 18:22:03.000000000 +0200
@@ -831,6 +831,7 @@
     # test pdb
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.completenames = lambda *ignore: ['baba']
     kernel.shell.pdb_session = pdb_obj
     match = kernel.do_complete('ba', 2)
@@ -889,6 +890,7 @@
     """
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.curframe_locals = pdb_obj.curframe.f_locals
     kernel.shell.pdb_session = pdb_obj
 
@@ -915,6 +917,7 @@
     """
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.curframe_locals = pdb_obj.curframe.f_locals
     kernel.shell.pdb_session = pdb_obj
 
@@ -941,6 +944,7 @@
     kernel.shell.user_ns["test"] = 0
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.curframe_locals = pdb_obj.curframe.f_locals
     kernel.shell.pdb_session = pdb_obj
 
@@ -1022,6 +1026,7 @@
     baba = 1
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.curframe_locals = pdb_obj.curframe.f_locals
     kernel.shell.pdb_session = pdb_obj
 
@@ -1059,6 +1064,7 @@
     a = 1
     pdb_obj = SpyderPdb()
     pdb_obj.curframe = inspect.currentframe()
+    pdb_obj.prompt_waiting = True
     pdb_obj.curframe_locals = pdb_obj.curframe.f_locals
     kernel.shell.pdb_session = pdb_obj
 
@@ -1116,6 +1122,8 @@
         if backend is not None:
             client.execute("%matplotlib {}".format(backend))
             client.get_shell_msg(timeout=TIMEOUT)
+            client.execute("import time; time.sleep(.1)")
+            client.get_shell_msg(timeout=TIMEOUT)
 
         # Get backend
         code = "backend = get_ipython().kernel.get_mpl_interactive_backend()"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/customize/namespace_manager.py 
new/spyder-kernels-2.3.2/spyder_kernels/customize/namespace_manager.py
--- old/spyder-kernels-2.3.1/spyder_kernels/customize/namespace_manager.py      
2022-05-21 18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/customize/namespace_manager.py      
2022-07-06 18:22:03.000000000 +0200
@@ -6,6 +6,7 @@
 
 import linecache
 import os.path
+import types
 import sys
 
 from IPython.core.getipython import get_ipython
@@ -13,6 +14,25 @@
 from spyder_kernels.py3compat import PY2
 
 
+def new_main_mod(filename, modname):
+    """
+    Reimplemented from IPython/core/interactiveshell.py to avoid caching
+    and clearing recursive namespace.
+    """
+    filename = os.path.abspath(filename)
+
+    main_mod = types.ModuleType(
+        modname,
+        doc="Module created for script run in IPython")
+
+    main_mod.__file__ = filename
+    # It seems pydoc (and perhaps others) needs any module instance to
+    # implement a __nonzero__ method
+    main_mod.__nonzero__ = lambda : True
+
+    return main_mod
+
+
 class NamespaceManager(object):
     """
     Get a namespace and set __file__ to filename for this namespace.
@@ -29,6 +49,7 @@
         self.current_namespace = current_namespace
         self._previous_filename = None
         self._previous_main = None
+        self._previous_running_namespace = None
         self._reset_main = False
         self._file_code = file_code
         ipython_shell = get_ipython()
@@ -49,9 +70,7 @@
                     self._previous_filename = self.ns_globals['__file__']
                 self.ns_globals['__file__'] = self.filename
             else:
-
-                main_mod = ipython_shell.new_main_mod(
-                    self.filename, '__main__')
+                main_mod = new_main_mod(self.filename, '__main__')
                 self.ns_globals = main_mod.__dict__
                 self.ns_locals = None
                 # Needed to allow pickle to reference main
@@ -61,6 +80,8 @@
                 self._reset_main = True
 
         # Save current namespace for access by variable explorer
+        self._previous_running_namespace = (
+            ipython_shell.kernel._running_namespace)
         ipython_shell.kernel._running_namespace = (
             self.ns_globals, self.ns_locals)
 
@@ -86,7 +107,8 @@
         Reset the namespace.
         """
         ipython_shell = get_ipython()
-        ipython_shell.kernel._running_namespace = None
+        ipython_shell.kernel._running_namespace = (
+            self._previous_running_namespace)
         if self._previous_filename:
             self.ns_globals['__file__'] = self._previous_filename
         elif '__file__' in self.ns_globals:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/customize/spydercustomize.py 
new/spyder-kernels-2.3.2/spyder_kernels/customize/spydercustomize.py
--- old/spyder-kernels-2.3.1/spyder_kernels/customize/spydercustomize.py        
2022-05-21 18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/customize/spydercustomize.py        
2022-07-06 18:22:03.000000000 +0200
@@ -13,7 +13,6 @@
 
 import ast
 import bdb
-import cmd
 import io
 import logging
 import os
@@ -23,17 +22,15 @@
 import time
 import warnings
 
-from IPython import __version__ as ipy_version
 from IPython.core.getipython import get_ipython
 
-from spyder_kernels.comms.frontendcomm import CommError, frontend_request
+from spyder_kernels.comms.frontendcomm import 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)
+    PY2, _print, encode, compat_exec, FileNotFoundError)
+from spyder_kernels.customize.utils import capture_last_Expr, canonic
 
 if not PY2:
     from IPython.core.inputtransformer2 import (
@@ -330,18 +327,8 @@
 # =============================================================================
 # Pdb adjustments
 # =============================================================================
-def cmd_input(prompt=''):
-    return get_ipython().kernel.cmd_input(prompt)
-
-
 pdb.Pdb = SpyderPdb
 
-if PY2:
-    cmd.raw_input = cmd_input
-else:
-    cmd.input = cmd_input
-
-
 # =============================================================================
 # User module reloader
 # =============================================================================
@@ -505,18 +492,23 @@
         __tracebackhide__ = "__pdb_exit__"
 
 
-def get_file_code(filename, save_all=True):
-    """Retrive the content of a file."""
+def get_file_code(filename, save_all=True, raise_exception=False):
+    """Retrieve the content of a file."""
     # Get code from spyder
     try:
-        file_code = frontend_request(blocking=True).get_file_code(
+        return frontend_request(blocking=True).get_file_code(
             filename, save_all=save_all)
-    except (CommError, TimeoutError, RuntimeError, FileNotFoundError):
-        file_code = None
-    if file_code is None:
-        with open(filename, 'r') as f:
-            return f.read()
-    return file_code
+    except Exception:
+        # Maybe this is a local file
+        try:
+            with open(filename, 'r') as f:
+                return f.read()
+        except FileNotFoundError:
+            pass
+        if raise_exception:
+            raise
+        # Else return None
+        return None
 
 
 def runfile(filename=None, args=None, wdir=None, namespace=None,
@@ -536,7 +528,7 @@
 
 def _exec_file(filename=None, args=None, wdir=None, namespace=None,
                post_mortem=False, current_namespace=False, stack_depth=0,
-               exec_fun=None):
+               exec_fun=None, canonic_filename=None):
     # Tell IPython to hide this frame (>7.16)
     __tracebackhide__ = True
     ipython_shell = get_ipython()
@@ -544,11 +536,6 @@
         filename = get_current_file_name()
         if filename is None:
             return
-    else:
-        # get_debugger replaces \\ by / so we must undo that here
-        # Otherwise code caching doesn't work
-        if os.name == 'nt':
-            filename = filename.replace('/', '\\')
 
     try:
         filename = filename.decode('utf-8')
@@ -562,22 +549,23 @@
         __umr__.run()
     if args is not None and not isinstance(args, basestring):
         raise TypeError("expected a character buffer object")
+
     try:
-        file_code = get_file_code(filename)
+        file_code = get_file_code(filename, raise_exception=True)
     except Exception:
+        # Show an error and return None
         _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")
-        return
 
-    # Normalise the filename
-    filename = os.path.abspath(filename)
-    filename = os.path.normcase(filename)
+    # Here the remote filename has been used. It must now be valid locally.
+    if canonic_filename is not None:
+        filename = canonic_filename
+    else:
+        filename = canonic(filename)
 
     with NamespaceManager(filename, namespace, current_namespace,
                           file_code=file_code, stack_depth=stack_depth + 1
@@ -655,7 +643,7 @@
     if shell.is_debugging():
         # Recursive
         code = (
-            "runfile({}".format(repr(normalise_filename(filename))) +
+            "runfile({}".format(repr(filename)) +
             ", args=%r, wdir=%r, current_namespace=%r)" % (
                 args, wdir, current_namespace)
         )
@@ -666,11 +654,13 @@
     else:
         debugger = get_new_debugger(filename, True)
         _exec_file(
-            filename=debugger.canonic(filename),
-            args=args, wdir=wdir,
+            filename=filename,
+            canonic_filename=debugger.canonic(filename),
+            args=args,
+            wdir=wdir,
             current_namespace=current_namespace,
             exec_fun=debugger.run,
-            stack_depth=1
+            stack_depth=1,
         )
 
 
@@ -696,7 +686,7 @@
 
 
 def _exec_cell(cellname, filename=None, post_mortem=False, stack_depth=0,
-               exec_fun=None):
+               exec_fun=None, canonic_filename=None):
     """
     Execute a code cell with a given exec function.
     """
@@ -706,11 +696,6 @@
         filename = get_current_file_name()
         if filename is None:
             return
-    else:
-        # get_debugger replaces \\ by / so we must undo that here
-        # Otherwise code caching doesn't work
-        if os.name == 'nt':
-            filename = filename.replace('/', '\\')
     try:
         filename = filename.decode('utf-8')
     except (UnicodeError, TypeError, AttributeError):
@@ -736,14 +721,14 @@
     # Trigger `post_execute` to exit the additional pre-execution.
     # See Spyder PR #7310.
     ipython_shell.events.trigger('post_execute')
-    try:
-        file_code = get_file_code(filename, save_all=False)
-    except Exception:
-        file_code = None
+    file_code = get_file_code(filename, save_all=False)
 
-    # Normalise the filename
-    filename = os.path.abspath(filename)
-    filename = os.path.normcase(filename)
+    # Here the remote filename has been used. It must now be valid locally.
+    if canonic_filename is not None:
+        filename = canonic_filename
+    else:
+        # Normalise the filename
+        filename = canonic(filename)
 
     with NamespaceManager(filename, current_namespace=True,
                           file_code=file_code, stack_depth=stack_depth + 1
@@ -770,7 +755,7 @@
         # Recursive
         code = (
             "runcell({}, ".format(repr(cellname)) +
-            "{})".format(repr(normalise_filename(filename)))
+            "{})".format(repr(filename))
         )
         shell.pdb_session.enter_recursive_debugger(
             code, filename, False,
@@ -779,7 +764,8 @@
         debugger = get_new_debugger(filename, False)
         _exec_cell(
             cellname=cellname,
-            filename=debugger.canonic(filename),
+            filename=filename,
+            canonic_filename=debugger.canonic(filename),
             exec_fun=debugger.run,
             stack_depth=1
         )
@@ -814,12 +800,15 @@
 
 
 # =============================================================================
-# Extend sys.path with paths that come from Spyder
+# PYTHONPATH and sys.path Adjustments
 # =============================================================================
+# PYTHONPATH is not passed to kernel directly, see spyder-ide/spyder#13519
+# This allows the kernel to start without crashing if modules in PYTHONPATH
+# shadow standard library modules.
 def set_spyder_pythonpath():
     pypath = os.environ.get('SPY_PYTHONPATH')
     if pypath:
-        pathlist = pypath.split(os.pathsep)
-        sys.path.extend(pathlist)
+        sys.path.extend(pypath.split(os.pathsep))
+        os.environ.update({'PYTHONPATH': pypath})
 
 set_spyder_pythonpath()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/customize/spyderpdb.py 
new/spyder-kernels-2.3.2/spyder_kernels/customize/spyderpdb.py
--- old/spyder-kernels-2.3.1/spyder_kernels/customize/spyderpdb.py      
2022-05-21 18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/customize/spyderpdb.py      
2022-07-06 18:22:03.000000000 +0200
@@ -1,3 +1,4 @@
+# -*- coding: utf-8 -*-
 #
 # Copyright (c) 2009- Spyder Kernels Contributors
 #
@@ -9,9 +10,9 @@
 import ast
 import bdb
 import logging
-import os
 import sys
 import traceback
+import threading
 from collections import namedtuple
 
 from IPython.core.autocall import ZMQExitAutocall
@@ -20,7 +21,8 @@
 
 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
+from spyder_kernels.py3compat import (
+    TimeoutError, PY2, _print, isidentifier, PY3, input)
 
 if not PY2:
     from IPython.core.inputtransformer2 import TransformerManager
@@ -92,10 +94,23 @@
         self._pdb_breaking = False
         self._frontend_notified = False
 
+        # content of tuple: (filename, line number)
+        self._previous_step = None
+
         # Don't report hidden frames for IPython 7.24+. This attribute
         # has no effect in previous versions.
         self.report_skipped = False
 
+
+        # Keep track of remote filename
+        self.remote_filename = None
+
+        # State of the prompt
+        self.prompt_waiting = False
+
+        # Line received from the frontend
+        self._cmd_input_line = None
+
     # --- Methods overriden for code execution
     def print_exclamation_warning(self):
         """Print pdb warning for exclamation mark."""
@@ -107,10 +122,6 @@
     def default(self, line):
         """
         Default way of running pdb statment.
-
-        The only difference with Pdb.default is that if line contains multiple
-        statments, the code will be compiled with 'exec'. It will not print the
-        result but will run without failing.
         """
         execute_events = self.pdb_execute_events
         if line[:1] == '!':
@@ -542,6 +553,12 @@
         return result
 
     # --- Methods overriden by us for Spyder integration
+    def postloop(self):
+        # postloop() is called when the debugger???s input prompt exists. Reset
+        # _previous_step so that publish_pdb_state() actually notifies Spyder
+        # about a changed frame the next the input prompt is entered again.
+        self._previous_step = None
+
     def preloop(self):
         """Ask Spyder for breakpoints before the first prompt is created."""
         try:
@@ -554,7 +571,7 @@
             if self.starting:
                 self.set_spyder_breakpoints(pdb_settings['breakpoints'])
             if self.send_initial_notification:
-                self.notify_spyder()
+                self.publish_pdb_state()
         except (CommError, TimeoutError):
             logger.debug("Could not get breakpoints from the frontend.")
         super(SpyderPdb, self).preloop()
@@ -625,6 +642,75 @@
                        "For copying text while debugging, use Ctrl+Shift+C",
                        file=self.stdout)
 
+
+    def cmdloop(self, intro=None):
+        """
+        Repeatedly issue a prompt, accept input, parse an initial prefix
+        off the received input, and dispatch to action methods, passing them
+        the remainder of the line as argument.
+        """
+        self.preloop()
+        if intro is not None:
+            self.intro = intro
+        if self.intro:
+            self.stdout.write(str(self.intro)+"\n")
+        stop = None
+        while not stop:
+            if self.cmdqueue:
+                line = self.cmdqueue.pop(0)
+            else:
+                try:
+                    self.prompt_waiting = True
+                    line = self.cmd_input(self.prompt)
+                except EOFError:
+                    line = 'EOF'
+            self.prompt_waiting = False
+            line = self.precmd(line)
+            stop = self.onecmd(line)
+            stop = self.postcmd(stop, line)
+        self.postloop()
+
+    def cmd_input(self, prompt=''):
+        """
+        Get input from frontend. Blocks until return
+        """
+        kernel = get_ipython().kernel
+        # Only works if the comm is open
+        if not kernel.frontend_comm.is_open():
+            return input(prompt)
+
+        # Flush output before making the request.
+        sys.stderr.flush()
+        sys.stdout.flush()
+
+        # Send the input request.
+        self._cmd_input_line = None
+        kernel.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)
+
+        # Get input by running eventloop
+        if is_main_thread and kernel.eventloop:
+            while self._cmd_input_line is None:
+                eventloop = kernel.eventloop
+                if eventloop:
+                    eventloop(kernel)
+                else:
+                    break
+
+        # Get input by blocking
+        if self._cmd_input_line is None:
+            kernel.frontend_comm.wait_until(
+                lambda: self._cmd_input_line is not None)
+
+        return self._cmd_input_line
+
     def precmd(self, line):
         """
         Hook method executed just before the command line is
@@ -644,9 +730,11 @@
 
     def postcmd(self, stop, line):
         """
-        Notify spyder on any pdb command.
+        Notify spyder about (possibly) changed frame
+
+        Note: The PDB commands ???up???, ???down??? and ???jump??? change the 
current frame.
         """
-        self.notify_spyder()
+        self.publish_pdb_state()
         return super(SpyderPdb, self).postcmd(stop, line)
 
     if PY2:
@@ -743,11 +831,16 @@
                     logger.debug(
                         "Could not send a Pdb continue call to the frontend.")
 
-    def notify_spyder(self):
-        """Send kernel state to the frontend."""
+    def publish_pdb_state(self):
+        """
+        Send debugger state (frame position) to the frontend.
+
+        The state is only sent if it has changed since the last update.
+        """
 
         frame = self.curframe
         if frame is None:
+            self._previous_step = None
             return
 
         # Get filename and line number of the current frame
@@ -757,14 +850,24 @@
                 fname = unicode(fname, "utf-8")
             except TypeError:
                 pass
+        if fname == self.mainpyfile and self.remote_filename is not None:
+            fname = self.remote_filename
         lineno = frame.f_lineno
 
+        if self._previous_step == (fname, lineno):
+            return
+
         # Set step of the current frame (if any)
         step = {}
+        self._previous_step = None
         if isinstance(fname, basestring) and isinstance(lineno, int):
             step = dict(fname=fname, lineno=lineno)
+            self._previous_step = (fname, lineno)
 
-        get_ipython().kernel.publish_pdb_state(step)
+        try:
+            frontend_request(blocking=False).pdb_state(dict(step=step))
+        except (CommError, TimeoutError):
+            logger.debug("Could not send Pdb state to the frontend.")
 
     def run(self, cmd, globals=None, locals=None):
         """Debug a statement executed via the exec() function.
@@ -808,11 +911,8 @@
         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.set_remote_filename(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))
@@ -821,14 +921,22 @@
         self.lastcmd = debugger.lastcmd
         get_ipython().pdb_session = self
 
+        # Reset _previous_step so that publish_pdb_state() called from within
+        # postcmd() notifies Spyder about a changed debugger position. The 
reset
+        # is required because the recursive debugger might change the position,
+        # but the parent debugger (self) is not aware of this.
+        self._previous_step = None
+
+    def set_remote_filename(self, filename):
+        """Set remote filename to signal Spyder on mainpyfile."""
+        self.remote_filename = filename
+        self.mainpyfile = self.canonic(filename)
+        self._wait_for_mainpyfile = True
+
 
 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.set_remote_filename(filename)
     debugger.continue_if_has_breakpoints = continue_if_has_breakpoints
-    debugger._user_requested_quit = False
     return debugger
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/customize/utils.py 
new/spyder-kernels-2.3.2/spyder_kernels/customize/utils.py
--- old/spyder-kernels-2.3.1/spyder_kernels/customize/utils.py  2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/customize/utils.py  2022-07-06 
18:22:03.000000000 +0200
@@ -117,9 +117,15 @@
     return code_ast, capture_last_expression
 
 
-def normalise_filename(filename):
-    """Normalise path for window."""
-    # Recursive
-    if os.name == 'nt':
-        return filename.replace('\\', '/')
-    return filename
+def canonic(filename):
+    """
+    Return canonical form of filename.
+
+    This is a copy of bdb.canonic, so that the debugger will process 
+    filenames in the same way
+    """
+    if filename == "<" + filename[1:-1] + ">":
+        return filename
+    canonic = os.path.abspath(filename)
+    canonic = os.path.normcase(canonic)
+    return canonic
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/utils/dochelpers.py 
new/spyder-kernels-2.3.2/spyder_kernels/utils/dochelpers.py
--- old/spyder-kernels-2.3.1/spyder_kernels/utils/dochelpers.py 2022-05-21 
18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/utils/dochelpers.py 2022-07-06 
18:22:03.000000000 +0200
@@ -238,7 +238,8 @@
         func_obj = getattr(obj, '__init__')
     else:
         return []
-    if not hasattr(func_obj, 'func_code'):
+
+    if not hasattr(func_obj, '__code__'):
         # Builtin: try to extract info from doc
         args = getargsfromdoc(func_obj)
         if args is not None:
@@ -246,24 +247,29 @@
         else:
             # Example: PyQt5
             return getargsfromdoc(obj)
-    args, _, _ = inspect.getargs(func_obj.func_code)
+
+    args, _, _ = inspect.getargs(func_obj.__code__)
     if not args:
         return getargsfromdoc(obj)
-    
+
     # Supporting tuple arguments in def statement:
     for i_arg, arg in enumerate(args):
         if isinstance(arg, list):
             args[i_arg] = "(%s)" % ", ".join(arg)
-            
+
     defaults = get_func_defaults(func_obj)
     if defaults is not None:
         for index, default in enumerate(defaults):
-            args[index+len(args)-len(defaults)] += '='+repr(default)
+            args[index + len(args) - len(defaults)] += '=' + repr(default)
+
     if inspect.isclass(obj) or inspect.ismethod(obj):
         if len(args) == 1:
             return None
-        if 'self' in args:
-            args.remove('self')
+
+    # Remove 'self' from args
+    if 'self' in args:
+        args.remove('self')
+
     return args
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/spyder-kernels-2.3.1/spyder_kernels/utils/tests/test_dochelpers.py 
new/spyder-kernels-2.3.2/spyder_kernels/utils/tests/test_dochelpers.py
--- old/spyder-kernels-2.3.1/spyder_kernels/utils/tests/test_dochelpers.py      
2022-05-21 18:36:00.000000000 +0200
+++ new/spyder-kernels-2.3.2/spyder_kernels/utils/tests/test_dochelpers.py      
2022-07-06 18:22:03.000000000 +0200
@@ -9,9 +9,9 @@
 """
 Tests for dochelpers.py
 """
+
 # Standard library imports
 import os
-import sys
 
 # Test library imports
 import pytest
@@ -27,57 +27,29 @@
         pass
 
 
-@pytest.mark.skipif(not PY2, reason="It fails in Python 3")
+@pytest.mark.skipif(PY2 or os.name == 'nt',
+                    reason="Only works on Linux and Mac")
 def test_dochelpers():
     """Test dochelpers."""
+    assert getargtxt(Test.method) == ['x, ', 'y=2']
     assert not getargtxt(Test.__init__)
-    if PY2:                    
-        assert getargtxt(Test.method) == ['x, ', 'y=2']
-        assert getdoc(sorted) == {'note': 'Function of __builtin__ module',
-                                  'argspec': u'(iterable, cmp=None, key=None, '
-                                              'reverse=False)',
-                                  'docstring': u'sorted(iterable, cmp=None, '
-                                                'key=None, reverse=False) --> '
-                                                'new sorted list',
-                                  'name': 'sorted'}
-        assert getargtxt(sorted) == ['iterable, ', ' cmp=None, ',
-                                     ' key=None, ', ' reverse=False']
-    else:
-        assert not getargtxt(Test.method)
-        if os.name == 'nt':
-            assert getdoc(sorted) == {'note': 'Function of builtins module',
-                                      'argspec': '(...)',
-                                      'docstring': 'Return a new list '
-                                                   'containing '
-                                                   'all items from the '
-                                                   'iterable in ascending '
-                                                   'order.\n\nA custom '
-                                                   'key function can be '
-                                                   'supplied to customise the '
-                                                   'sort order, and '
-                                                   'the\nreverse flag can be '
-                                                   'set to request the result '
-                                                   'in descending order.',
-                                      'name': 'sorted'}
-        else:
-            assert getdoc(sorted) == {'note': 'Function of builtins module',
-                                      'argspec': '(...)',
-                                      'docstring': 'Return a new list '
-                                                   'containing '
-                                                   'all items from the '
-                                                   'iterable in ascending '
-                                                   'order.\n\nA custom '
-                                                   'key function can be '
-                                                   'supplied to customize the '
-                                                   'sort order, and '
-                                                   'the\nreverse flag can be '
-                                                   'set to request the result '
-                                                   'in descending order.',
-                                      'name': 'sorted'}
-        assert not getargtxt(sorted)
+
+    assert getdoc(sorted) == {
+        'note': 'Function of builtins module',
+        'argspec': '(...)',
+        'docstring': 'Return a new list containing all items from the '
+                     'iterable in ascending order.\n\nA custom key function '
+                     'can be supplied to customize the sort order, and the\n'
+                     'reverse flag can be set to request the result in '
+                     'descending order.',
+        'name': 'sorted'
+    }
+    assert not getargtxt(sorted)
+
     assert isdefined('numpy.take', force_import=True)
     assert isdefined('__import__')
-    assert not isdefined('.keys', force_import=True)
+    assert not isdefined('zzz', force_import=True)
+
     assert getobj('globals') == 'globals'
     assert not getobj('globals().keys')
     assert getobj('+scipy.signal.') == 'scipy.signal'

Reply via email to