Script 'mail_helper' called by obssrc
Hello community,

here is the log from the commit of package python-ipython for openSUSE:Factory 
checked in at 2021-11-15 15:26:10
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-ipython (Old)
 and      /work/SRC/openSUSE:Factory/.python-ipython.new.1890 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-ipython"

Mon Nov 15 15:26:10 2021 rev:24 rq:931191 version:7.29.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-ipython/python-ipython.changes    
2021-10-25 15:17:22.969673735 +0200
+++ /work/SRC/openSUSE:Factory/.python-ipython.new.1890/python-ipython.changes  
2021-11-15 15:27:43.309845703 +0100
@@ -1,0 +2,26 @@
+Fri Nov 12 21:30:44 UTC 2021 - Ben Greiner <c...@bnavigator.de>
+
+- Update to 7.29.0
+  * IPython 7.29 brings a couple of new functionalities to IPython
+    and a number of bugfixes. It is one of the largest recent
+    release, relatively speaking, with close to 15 Pull Requests.
+  * fix an issue where base64 was returned instead of bytes when
+    showing figures
+  * fix compatibility with PyQt6, PySide 6. This
+    may be of interest if you are running on Apple Silicon as only
+    qt6.2+ is natively compatible.
+  * fix matplotlib qtagg eventloop
+  * Multiple docs fixes, typos, ... etc.
+  * Debugger will now exit by default on SigInt
+    this will be useful in notebook/lab if you forgot to exit the
+    debugger. "Interrupt Kernel" will now exist the debugger.
+  * It give Pdb the ability to skip code in decorators. If
+    functions contain a special value names __debuggerskip__ =
+    True|False, the function will not be stepped into, and Pdb will
+    step into lower frames only if the value is set to False. The
+    exact behavior is still likely to have corner cases and will be
+    refined in subsequent releases. Feedback welcome. See the
+    debugger module documentation for more info. Thanks to the D.
+    E. Shaw group for funding this feature.
+
+-------------------------------------------------------------------

Old:
----
  ipython-7.28.0.tar.gz

New:
----
  ipython-7.29.0.tar.gz

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

Other differences:
------------------
++++++ python-ipython.spec ++++++
--- /var/tmp/diff_new_pack.UBTpiu/_old  2021-11-15 15:27:43.857845857 +0100
+++ /var/tmp/diff_new_pack.UBTpiu/_new  2021-11-15 15:27:43.861845857 +0100
@@ -36,7 +36,7 @@
 %define         skip_python36 1
 %bcond_without  iptest
 Name:           python-ipython%{psuffix}
-Version:        7.28.0
+Version:        7.29.0
 Release:        0
 Summary:        Rich architecture for interactive computing with Python
 License:        BSD-3-Clause


++++++ ipython-7.28.0.tar.gz -> ipython-7.29.0.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/application.py 
new/ipython-7.29.0/IPython/core/application.py
--- old/ipython-7.28.0/IPython/core/application.py      2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/application.py      2021-10-30 
02:22:27.000000000 +0200
@@ -374,7 +374,7 @@
                     self.log.fatal("Profile %r not found."%self.profile)
                     self.exit(1)
             else:
-                self.log.debug("Using existing profile dir: %r"%p.location)
+                self.log.debug(f"Using existing profile dir: {p.location!r}")
         else:
             location = self.config.ProfileDir.location
             # location is fully specified
@@ -394,7 +394,7 @@
                     self.log.fatal("Profile directory %r not found."%location)
                     self.exit(1)
             else:
-                self.log.info("Using existing profile dir: %r"%location)
+                self.log.debug(f"Using existing profile dir: {p.location!r}")
             # if profile_dir is specified explicitly, set profile name
             dir_name = os.path.basename(p.location)
             if dir_name.startswith('profile_'):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/completer.py 
new/ipython-7.29.0/IPython/core/completer.py
--- old/ipython-7.28.0/IPython/core/completer.py        2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/completer.py        2021-10-30 
02:22:27.000000000 +0200
@@ -1496,7 +1496,7 @@
                   inspect.Parameter.POSITIONAL_OR_KEYWORD)
 
         try:
-            sig = inspect.signature(call_obj)
+            sig = inspect.signature(obj)
             ret.extend(k for k, v in sig.parameters.items() if
                        v.kind in _keeps)
         except ValueError:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/debugger.py 
new/ipython-7.29.0/IPython/core/debugger.py
--- old/ipython-7.28.0/IPython/core/debugger.py 2021-09-25 02:30:30.000000000 
+0200
+++ new/ipython-7.29.0/IPython/core/debugger.py 2021-10-30 02:22:27.000000000 
+0200
@@ -2,6 +2,76 @@
 """
 Pdb debugger class.
 
+
+This is an extension to PDB which adds a number of new features.
+Note that there is also the `IPython.terminal.debugger` class which provides UI
+improvements.
+
+We also strongly recommend to use this via the `ipdb` package, which provides
+extra configuration options.
+
+Among other things, this subclass of PDB:
+ - supports many IPython magics like pdef/psource
+ - hide frames in tracebacks based on `__tracebackhide__`
+ - allows to skip frames based on `__debuggerskip__`
+
+The skipping and hiding frames are configurable via the `skip_predicates`
+command.
+
+By default, frames from readonly files will be hidden, frames containing
+``__tracebackhide__=True`` will be hidden.
+
+Frames containing ``__debuggerskip__`` will be stepped over, frames who's 
parent
+frames value of ``__debuggerskip__`` is ``True`` will be skipped.
+
+    >>> def helpers_helper():
+    ...     pass
+    ...
+    ... def helper_1():
+    ...     print("don't step in me")
+    ...     helpers_helpers() # will be stepped over unless breakpoint set.
+    ...
+    ...
+    ... def helper_2():
+    ...     print("in me neither")
+    ...
+
+One can define a decorator that wraps a function between the two helpers:
+
+    >>> def pdb_skipped_decorator(function):
+    ...
+    ...
+    ...     def wrapped_fn(*args, **kwargs):
+    ...         __debuggerskip__ = True
+    ...         helper_1()
+    ...         __debuggerskip__ = False
+    ...         result = function(*args, **kwargs)
+    ...         __debuggerskip__ = True
+    ...         helper_2()
+    ...         # setting __debuggerskip__ to False again is not necessary
+    ...         return result
+    ...
+    ...     return wrapped_fn
+
+When decorating a function, ipdb will directly step into ``bar()`` by
+default:
+
+    >>> @foo_decorator
+    ... def bar(x, y):
+    ...     return x * y
+
+
+You can toggle the behavior with
+
+    ipdb> skip_predicates debuggerskip false
+
+or configure it in your ``.pdbrc``
+
+
+
+Licencse
+--------
+
 Modified from the standard pdb.Pdb class to avoid including readline, so that
 the command line completion of other programs which include this isn't
 damaged.
@@ -9,11 +79,16 @@
 In the future, this class will be expanded with improvements over the standard
 pdb.
 
-The code in this file is mainly lifted out of cmd.py in Python 2.2, with minor
-changes. Licensing should therefore be under the standard Python terms.  For
-details on the PSF (Python Software Foundation) standard license, see:
+The original code in this file is mainly lifted out of cmd.py in Python 2.2,
+with minor changes. Licensing should therefore be under the standard Python
+terms.  For details on the PSF (Python Software Foundation) standard license,
+see:
 
 https://docs.python.org/2/license.html
+
+
+All the changes since then are under the same license as IPython.
+
 """
 
 #*****************************************************************************
@@ -51,6 +126,9 @@
 # it does so with some limitations.  The rest of this support is implemented in
 # the Tracer constructor.
 
+DEBUGGERSKIP = "__debuggerskip__"
+
+
 def make_arrow(pad):
     """generate the leading arrow in front of traceback or debugger"""
     if pad >= 2:
@@ -206,7 +284,12 @@
 
     """
 
-    default_predicates = {"tbhide": True, "readonly": False, 
"ipython_internal": True}
+    default_predicates = {
+        "tbhide": True,
+        "readonly": False,
+        "ipython_internal": True,
+        "debuggerskip": True,
+    }
 
     def __init__(self, color_scheme=None, completekey=None,
                  stdin=None, stdout=None, context=5, **kwargs):
@@ -305,6 +388,7 @@
         # list of predicates we use to skip frames
         self._predicates = self.default_predicates
 
+    #
     def set_colors(self, scheme):
         """Shorthand access to the color table scheme selector method."""
         self.color_scheme_table.set_active_scheme(scheme)
@@ -804,10 +888,61 @@
 
     do_w = do_where
 
+    def break_anywhere(self, frame):
+        """
+
+        _stop_in_decorator_internals is overly restrictive, as we may still 
want
+        to trace function calls, so we need to also update break_anywhere so
+        that is we don't `stop_here`, because of debugger skip, we may still
+        stop at any point inside the function
+
+        """
+
+        sup = super().break_anywhere(frame)
+        if sup:
+            return sup
+        if self._predicates["debuggerskip"]:
+            if DEBUGGERSKIP in frame.f_code.co_varnames:
+                return True
+            if frame.f_back and 
self._get_frame_locals(frame.f_back).get(DEBUGGERSKIP):
+                return True
+        return False
+
+    @skip_doctest
+    def _is_in_decorator_internal_and_should_skip(self, frame):
+        """
+        Utility to tell us whether we are in a decorator internal and should 
stop.
+
+
+
+        """
+
+        # if we are disabled don't skip
+        if not self._predicates["debuggerskip"]:
+            return False
+
+        # if frame is tagged, skip by default.
+        if DEBUGGERSKIP in frame.f_code.co_varnames:
+            return True
+
+        # if one of the parent frame value set to True skip as well.
+
+        cframe = frame
+        while getattr(cframe, "f_back", None):
+            cframe = cframe.f_back
+            if self._get_frame_locals(cframe).get(DEBUGGERSKIP):
+                return True
+
+        return False
+
     def stop_here(self, frame):
         """Check if pdb should stop here"""
         if not super().stop_here(frame):
             return False
+
+        if self._is_in_decorator_internal_and_should_skip(frame) is True:
+            return False
+
         hidden = False
         if self.skip_hidden:
             hidden = self._hidden_predicate(frame)
@@ -929,10 +1064,10 @@
 class InterruptiblePdb(Pdb):
     """Version of debugger where KeyboardInterrupt exits the debugger 
altogether."""
 
-    def cmdloop(self):
+    def cmdloop(self, intro=None):
         """Wrap cmdloop() such that KeyboardInterrupt stops the debugger."""
         try:
-            return OldPdb.cmdloop(self)
+            return OldPdb.cmdloop(self, intro=intro)
         except KeyboardInterrupt:
             self.stop_here = lambda frame: False
             self.do_quit("")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/interactiveshell.py 
new/ipython-7.29.0/IPython/core/interactiveshell.py
--- old/ipython-7.28.0/IPython/core/interactiveshell.py 2021-09-25 
02:30:37.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/interactiveshell.py 2021-10-30 
02:22:27.000000000 +0200
@@ -43,7 +43,7 @@
 from IPython.core.builtin_trap import BuiltinTrap
 from IPython.core.events import EventManager, available_events
 from IPython.core.compilerop import CachingCompiler, check_linecache_ipython
-from IPython.core.debugger import Pdb
+from IPython.core.debugger import InterruptiblePdb
 from IPython.core.display_trap import DisplayTrap
 from IPython.core.displayhook import DisplayHook
 from IPython.core.displaypub import DisplayPublisher
@@ -1823,7 +1823,7 @@
     # Things related to exception handling and tracebacks (not debugging)
     #-------------------------------------------------------------------------
 
-    debugger_cls = Pdb
+    debugger_cls = InterruptiblePdb
 
     def init_traceback_handlers(self, custom_exceptions):
         # Syntax error handler.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/pylabtools.py 
new/ipython-7.29.0/IPython/core/pylabtools.py
--- old/ipython-7.28.0/IPython/core/pylabtools.py       2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/pylabtools.py       2021-10-30 
02:22:27.000000000 +0200
@@ -5,6 +5,8 @@
 # Distributed under the terms of the Modified BSD License.
 
 from io import BytesIO
+from binascii import b2a_base64
+from functools import partial
 import warnings
 
 from IPython.core.display import _pngxy
@@ -39,8 +41,6 @@
 # most part it's just a reverse of the above dict, but we also need to add a
 # few others that map to the same GUI manually:
 backend2gui = dict(zip(backends.values(), backends.keys()))
-# Our tests expect backend2gui to just return 'qt'
-backend2gui['Qt4Agg'] = 'qt'
 # In the reverse mapping, there are a few extra valid matplotlib backends that
 # map to the same GUI support
 backend2gui["GTK"] = backend2gui["GTKCairo"] = "gtk"
@@ -48,6 +48,13 @@
 backend2gui["GTK4Cairo"] = "gtk4"
 backend2gui["WX"] = "wx"
 backend2gui["CocoaAgg"] = "osx"
+# There needs to be a hysteresis here as the new QtAgg Matplotlib backend
+# supports either Qt5 or Qt6 and the IPython qt event loop support Qt4, Qt5,
+# and Qt6.
+backend2gui["QtAgg"] = "qt"
+backend2gui["Qt4Agg"] = "qt"
+backend2gui["Qt5Agg"] = "qt"
+
 # And some backends that don't need GUI integration
 del backend2gui["nbAgg"]
 del backend2gui["agg"]
@@ -55,6 +62,7 @@
 del backend2gui["pdf"]
 del backend2gui["ps"]
 del backend2gui["module://matplotlib_inline.backend_inline"]
+del backend2gui["module://ipympl.backend_nbagg"]
 
 #-----------------------------------------------------------------------------
 # Matplotlib utilities
@@ -99,7 +107,7 @@
     matplotlib.rcParams['figure.figsize'] = [sizex, sizey]
 
 
-def print_figure(fig, fmt='png', bbox_inches='tight', **kwargs):
+def print_figure(fig, fmt="png", bbox_inches="tight", base64=False, **kwargs):
     """Print a figure to an image, and return the resulting file data
 
     Returned data will be bytes unless ``fmt='svg'``,
@@ -107,6 +115,12 @@
 
     Any keyword args are passed to fig.canvas.print_figure,
     such as ``quality`` or ``bbox_inches``.
+
+    If `base64` is True, return base64-encoded str instead of raw bytes
+    for binary-encoded image formats
+
+    .. versionadded: 7.29
+        base64 argument
     """
     # When there's an empty figure, we shouldn't return anything, otherwise we
     # get big blank areas in the qt console.
@@ -138,19 +152,31 @@
     data = bytes_io.getvalue()
     if fmt == 'svg':
         data = data.decode('utf-8')
+    elif base64:
+        data = b2a_base64(data).decode("ascii")
     return data
 
-def retina_figure(fig, **kwargs):
-    """format a figure as a pixel-doubled (retina) PNG"""
-    pngdata = print_figure(fig, fmt='retina', **kwargs)
+def retina_figure(fig, base64=False, **kwargs):
+    """format a figure as a pixel-doubled (retina) PNG
+
+    If `base64` is True, return base64-encoded str instead of raw bytes
+    for binary-encoded image formats
+
+    .. versionadded: 7.29
+        base64 argument
+    """
+    pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs)
     # Make sure that retina_figure acts just like print_figure and returns
     # None when the figure is empty.
     if pngdata is None:
         return
     w, h = _pngxy(pngdata)
     metadata = {"width": w//2, "height":h//2}
+    if base64:
+        pngdata = b2a_base64(pngdata).decode("ascii")
     return pngdata, metadata
 
+
 # We need a little factory function here to create the closure where
 # safe_execfile can live.
 def mpl_runner(safe_execfile):
@@ -249,16 +275,22 @@
         gs = "%s" % ','.join([repr(f) for f in supported])
         raise ValueError("supported formats are: %s not %s" % (gs, bs))
 
-    if 'png' in formats:
-        png_formatter.for_type(Figure, lambda fig: print_figure(fig, 'png', 
**kwargs))
-    if 'retina' in formats or 'png2x' in formats:
-        png_formatter.for_type(Figure, lambda fig: retina_figure(fig, 
**kwargs))
-    if 'jpg' in formats or 'jpeg' in formats:
-        jpg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'jpg', 
**kwargs))
-    if 'svg' in formats:
-        svg_formatter.for_type(Figure, lambda fig: print_figure(fig, 'svg', 
**kwargs))
-    if 'pdf' in formats:
-        pdf_formatter.for_type(Figure, lambda fig: print_figure(fig, 'pdf', 
**kwargs))
+    if "png" in formats:
+        png_formatter.for_type(
+            Figure, partial(print_figure, fmt="png", base64=True, **kwargs)
+        )
+    if "retina" in formats or "png2x" in formats:
+        png_formatter.for_type(Figure, partial(retina_figure, base64=True, 
**kwargs))
+    if "jpg" in formats or "jpeg" in formats:
+        jpg_formatter.for_type(
+            Figure, partial(print_figure, fmt="jpg", base64=True, **kwargs)
+        )
+    if "svg" in formats:
+        svg_formatter.for_type(Figure, partial(print_figure, fmt="svg", 
**kwargs))
+    if "pdf" in formats:
+        pdf_formatter.for_type(
+            Figure, partial(print_figure, fmt="pdf", base64=True, **kwargs)
+        )
 
 #-----------------------------------------------------------------------------
 # Code for initializing matplotlib and importing pylab
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/release.py 
new/ipython-7.29.0/IPython/core/release.py
--- old/ipython-7.28.0/IPython/core/release.py  2021-09-25 02:32:53.000000000 
+0200
+++ new/ipython-7.29.0/IPython/core/release.py  2021-10-30 02:52:42.000000000 
+0200
@@ -20,7 +20,7 @@
 # release.  'dev' as a _version_extra string means this is a development
 # version
 _version_major = 7
-_version_minor = 28
+_version_minor = 29
 _version_patch = 0
 _version_extra = '.dev'
 # _version_extra = 'b1'
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/tests/test_debugger.py 
new/ipython-7.29.0/IPython/core/tests/test_debugger.py
--- old/ipython-7.28.0/IPython/core/tests/test_debugger.py      2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/tests/test_debugger.py      2021-10-30 
02:22:27.000000000 +0200
@@ -12,6 +12,7 @@
 import sys
 import time
 import warnings
+
 from subprocess import PIPE, CalledProcessError, check_output
 from tempfile import NamedTemporaryFile
 from textwrap import dedent
@@ -325,6 +326,191 @@
 
     child.close()
 
+
+skip_decorators_blocks = (
+    """
+    def helpers_helper():
+        pass # should not stop here except breakpoint
+    """,
+    """
+    def helper_1():
+        helpers_helper() # should not stop here
+    """,
+    """
+    def helper_2():
+        pass # should not stop here
+    """,
+    """
+    def pdb_skipped_decorator2(function):
+        def wrapped_fn(*args, **kwargs):
+            __debuggerskip__ = True
+            helper_2()
+            __debuggerskip__ = False
+            result = function(*args, **kwargs)
+            __debuggerskip__ = True
+            helper_2()
+            return result
+        return wrapped_fn
+    """,
+    """
+    def pdb_skipped_decorator(function):
+        def wrapped_fn(*args, **kwargs):
+            __debuggerskip__ = True
+            helper_1()
+            __debuggerskip__ = False
+            result = function(*args, **kwargs)
+            __debuggerskip__ = True
+            helper_2()
+            return result
+        return wrapped_fn
+    """,
+    """
+    @pdb_skipped_decorator
+    @pdb_skipped_decorator2
+    def bar(x, y):
+        return x * y
+    """,
+    """import IPython.terminal.debugger as ipdb""",
+    """
+    def f():
+        ipdb.set_trace()
+        bar(3, 4)
+    """,
+    """
+    f()
+    """,
+)
+
+
+def _decorator_skip_setup():
+    import pexpect
+
+    env = os.environ.copy()
+    env["IPY_TEST_SIMPLE_PROMPT"] = "1"
+
+    child = pexpect.spawn(
+        sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
+    )
+    child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
+
+    child.expect("IPython")
+    child.expect("\n")
+
+    dedented_blocks = [dedent(b).strip() for b in skip_decorators_blocks]
+    in_prompt_number = 1
+    for cblock in dedented_blocks:
+        child.expect_exact(f"In [{in_prompt_number}]:")
+        in_prompt_number += 1
+        for line in cblock.splitlines():
+            child.sendline(line)
+            child.expect_exact(line)
+        child.sendline("")
+    return child
+
+
+@skip_win32
+def test_decorator_skip():
+    """test that decorator frames can be skipped."""
+
+    child = _decorator_skip_setup()
+
+    child.expect_exact("3     bar(3, 4)")
+    child.expect("ipdb>")
+
+    child.expect("ipdb>")
+    child.sendline("step")
+    child.expect_exact("step")
+
+    child.expect_exact("1 @pdb_skipped_decorator")
+
+    child.sendline("s")
+    child.expect_exact("return x * y")
+
+    child.close()
+
+
+@skip_win32
+def test_decorator_skip_disabled():
+    """test that decorator frame skipping can be disabled"""
+
+    child = _decorator_skip_setup()
+
+    child.expect_exact("3     bar(3, 4)")
+
+    for input_, expected in [
+        ("skip_predicates debuggerskip False", ""),
+        ("skip_predicates", "debuggerskip : False"),
+        ("step", "---> 2     def wrapped_fn"),
+        ("step", "----> 3         __debuggerskip__"),
+        ("step", "----> 4         helper_1()"),
+        ("step", "---> 1 def helper_1():"),
+        ("next", "----> 2     helpers_helper()"),
+        ("next", "--Return--"),
+        ("next", "----> 5         __debuggerskip__ = False"),
+    ]:
+        child.expect("ipdb>")
+        child.sendline(input_)
+        child.expect_exact(input_)
+        child.expect_exact(expected)
+
+    child.close()
+
+
+@skip_win32
+def test_decorator_skip_with_breakpoint():
+    """test that decorator frame skipping can be disabled"""
+
+    import pexpect
+
+    env = os.environ.copy()
+    env["IPY_TEST_SIMPLE_PROMPT"] = "1"
+
+    child = pexpect.spawn(
+        sys.executable, ["-m", "IPython", "--colors=nocolor"], env=env
+    )
+    child.timeout = 5 * IPYTHON_TESTING_TIMEOUT_SCALE
+
+    child.expect("IPython")
+    child.expect("\n")
+
+    ### we need a filename, so we need to exec the full block with a filename
+    with NamedTemporaryFile(suffix=".py", dir=".", delete=True) as tf:
+
+        name = tf.name[:-3].split("/")[-1]
+        tf.write("\n".join([dedent(x) for x in 
skip_decorators_blocks[:-1]]).encode())
+        tf.flush()
+        codeblock = f"from {name} import f"
+
+        dedented_blocks = [
+            codeblock,
+            "f()",
+        ]
+
+        in_prompt_number = 1
+        for cblock in dedented_blocks:
+            child.expect_exact(f"In [{in_prompt_number}]:")
+            in_prompt_number += 1
+            for line in cblock.splitlines():
+                child.sendline(line)
+                child.expect_exact(line)
+            child.sendline("")
+
+        # as the filename does not exists, we'll rely on the filename prompt
+        child.expect_exact("47     bar(3, 4)")
+
+        for input_, expected in [
+            (f"b {name}.py:3", ""),
+            ("step", "1---> 3     pass # should not stop here except"),
+            ("step", "---> 38 @pdb_skipped_decorator"),
+            ("continue", ""),
+        ]:
+            child.expect("ipdb>")
+            child.sendline(input_)
+            child.expect_exact(input_)
+            child.expect_exact(expected)
+
+    child.close()
+
 
 @skip_win32
 def test_where_erase_value():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/tests/test_display.py 
new/ipython-7.29.0/IPython/core/tests/test_display.py
--- old/ipython-7.28.0/IPython/core/tests/test_display.py       2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/tests/test_display.py       2021-10-30 
02:22:27.000000000 +0200
@@ -187,10 +187,12 @@
     display.set_matplotlib_formats('png', **kwargs)
     formatter = ip.display_formatter.formatters['image/png']
     f = formatter.lookup_by_type(Figure)
-    cell = f.__closure__[0].cell_contents
+    formatter_kwargs = f.keywords
     expected = kwargs
+    expected["base64"] = True
+    expected["fmt"] = "png"
     expected.update(cfg.print_figure_kwargs)
-    nt.assert_equal(cell, expected)
+    nt.assert_equal(formatter_kwargs, expected)
 
 def test_display_available():
     """
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/tests/test_paths.py 
new/ipython-7.29.0/IPython/core/tests/test_paths.py
--- old/ipython-7.28.0/IPython/core/tests/test_paths.py 2021-04-18 
23:21:52.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/tests/test_paths.py 2021-10-30 
02:22:27.000000000 +0200
@@ -160,6 +160,10 @@
 @skip_win32
 def test_get_ipython_dir_8():
     """test_get_ipython_dir_8, test / home directory"""
+    if not os.access("/", os.W_OK):
+        # test only when HOME directory actually writable
+        return
+
     with patch.object(paths, '_writable_dir', lambda path: bool(path)), \
             patch.object(paths, 'get_xdg_dir', return_value=None), \
             modified_env({
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/tests/test_pylabtools.py 
new/ipython-7.29.0/IPython/core/tests/test_pylabtools.py
--- old/ipython-7.28.0/IPython/core/tests/test_pylabtools.py    2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/core/tests/test_pylabtools.py    2021-10-30 
02:22:27.000000000 +0200
@@ -5,7 +5,8 @@
 # Distributed under the terms of the Modified BSD License.
 
 
-from io import UnsupportedOperation, BytesIO
+from binascii import a2b_base64
+from io import BytesIO
 
 import matplotlib
 matplotlib.use('Agg')
@@ -104,8 +105,11 @@
     pt.select_figure_formats(ip, 'png', **kwargs)
     formatter = ip.display_formatter.formatters['image/png']
     f = formatter.lookup_by_type(Figure)
-    cell = f.__closure__[0].cell_contents
-    nt.assert_equal(cell, kwargs)
+    cell = f.keywords
+    expected = kwargs
+    expected["base64"] = True
+    expected["fmt"] = "png"
+    assert cell == expected
 
     # check that the formatter doesn't raise
     fig = plt.figure()
@@ -114,7 +118,9 @@
     plt.draw()
     formatter.enabled = True
     png = formatter(fig)
-    assert png.startswith(_PNG)
+    assert isinstance(png, str)
+    png_bytes = a2b_base64(png)
+    assert png_bytes.startswith(_PNG)
 
 def test_select_figure_formats_set():
     ip = get_ipython()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/core/usage.py 
new/ipython-7.29.0/IPython/core/usage.py
--- old/ipython-7.28.0/IPython/core/usage.py    2020-08-29 23:05:46.000000000 
+0200
+++ new/ipython-7.29.0/IPython/core/usage.py    2021-10-30 01:50:41.000000000 
+0200
@@ -305,7 +305,7 @@
 
 _i, _ii, _iii    : Previous, next previous, next next previous input
 _i4, _ih[2:5]    : Input history line 4, lines 2-4
-exec _i81        : Execute input history line #81 again
+exec(_i81)       : Execute input history line #81 again
 %rep 81          : Edit input history line #81
 _, __, ___       : previous, next previous, next next previous output
 _dh              : Directory history
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/paths.py 
new/ipython-7.29.0/IPython/paths.py
--- old/ipython-7.28.0/IPython/paths.py 2021-09-25 02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/paths.py 2021-10-30 02:22:27.000000000 +0200
@@ -66,6 +66,8 @@
             warn("IPython parent '{0}' is not a writable location,"
                     " using a temp directory.".format(parent))
             ipdir = tempfile.mkdtemp()
+        else:
+            os.makedirs(ipdir)
     assert isinstance(ipdir, str), "all path manipulation should be 
str(unicode), but are not."
     return ipdir
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/terminal/debugger.py 
new/ipython-7.29.0/IPython/terminal/debugger.py
--- old/ipython-7.28.0/IPython/terminal/debugger.py     2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/terminal/debugger.py     2021-10-30 
02:22:27.000000000 +0200
@@ -71,7 +71,7 @@
             enable_history_search=True,
             mouse_support=self.shell.mouse_support,
             complete_style=self.shell.pt_complete_style,
-            style=self.shell.style,
+            style=getattr(self.shell, "style", None),
             color_depth=self.shell.color_depth,
         )
 
@@ -96,7 +96,6 @@
         # prompt itself in a different thread (we can't start an event loop
         # within an event loop). This new thread won't have any event loop
         # running, and here we run our prompt-loop.
-
         self.preloop()
 
         try:
@@ -131,7 +130,6 @@
 
                     if keyboard_interrupt:
                         raise KeyboardInterrupt
-
                 line = self.precmd(line)
                 stop = self.onecmd(line)
                 stop = self.postcmd(stop, line)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/terminal/magics.py 
new/ipython-7.29.0/IPython/terminal/magics.py
--- old/ipython-7.28.0/IPython/terminal/magics.py       2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/terminal/magics.py       2021-10-30 
02:22:27.000000000 +0200
@@ -109,7 +109,7 @@
         Just press enter and type -- (and press enter again) and the block
         will be what was just pasted.
 
-        IPython statements (magics, shell escapes) are not supported (yet).
+        Shell escapes are not supported (yet).
 
         See also
         --------
@@ -122,9 +122,19 @@
           In [8]: %cpaste
           Pasting code; enter '--' alone on the line to stop.
           :>>> a = ["world!", "Hello"]
-          :>>> print " ".join(sorted(a))
+          :>>> print(" ".join(sorted(a)))
           :--
           Hello world!
+
+        ::
+          In [8]: %cpaste
+          Pasting code; enter '--' alone on the line to stop.
+          :>>> %alias_magic t timeit
+          :>>> %t -n1 pass
+          :--
+          Created `%t` as an alias for `%timeit`.
+          Created `%%t` as an alias for `%%timeit`.
+          354 ns ?? 224 ns per loop (mean ?? std. dev. of 7 runs, 1 loop each)
         """
         opts, name = self.parse_options(parameter_s, 'rqs:', mode='string')
         if 'r' in opts:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/terminal/pt_inputhooks/qt.py 
new/ipython-7.29.0/IPython/terminal/pt_inputhooks/qt.py
--- old/ipython-7.28.0/IPython/terminal/pt_inputhooks/qt.py     2021-09-25 
02:30:30.000000000 +0200
+++ new/ipython-7.29.0/IPython/terminal/pt_inputhooks/qt.py     2021-10-30 
02:22:27.000000000 +0200
@@ -64,7 +64,7 @@
         timer.timeout.connect(event_loop.quit)
         while not context.input_is_ready():
             timer.start(50)  # 50 ms
-            event_loop.exec_()
+            _exec(event_loop)
             timer.stop()
     else:
         # On POSIX platforms, we can use a file descriptor to quit the event
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/IPython/utils/_sysinfo.py 
new/ipython-7.29.0/IPython/utils/_sysinfo.py
--- old/ipython-7.28.0/IPython/utils/_sysinfo.py        2021-09-25 
02:32:53.000000000 +0200
+++ new/ipython-7.29.0/IPython/utils/_sysinfo.py        2021-10-30 
02:52:42.000000000 +0200
@@ -1,2 +1,2 @@
 # GENERATED BY setup.py
-commit = u"e76fa004a"
+commit = u"3813660de"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/PKG-INFO new/ipython-7.29.0/PKG-INFO
--- old/ipython-7.28.0/PKG-INFO 2021-09-25 02:32:53.000000000 +0200
+++ new/ipython-7.29.0/PKG-INFO 2021-10-30 02:52:42.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 1.1
 Name: ipython
-Version: 7.28.0
+Version: 7.29.0
 Summary: IPython: Productive Interactive Computing
 Home-page: https://ipython.org
 Author: The IPython Development Team
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ipython-7.28.0/docs/source/whatsnew/pr/enable-to-add-extra-attrs-to-iframe.rst
 
new/ipython-7.29.0/docs/source/whatsnew/pr/enable-to-add-extra-attrs-to-iframe.rst
--- 
old/ipython-7.28.0/docs/source/whatsnew/pr/enable-to-add-extra-attrs-to-iframe.rst
  2021-09-25 02:30:37.000000000 +0200
+++ 
new/ipython-7.29.0/docs/source/whatsnew/pr/enable-to-add-extra-attrs-to-iframe.rst
  1970-01-01 01:00:00.000000000 +0100
@@ -1,38 +0,0 @@
-``YouTubeVideo`` autoplay and the ability to add extra attributes to ``IFrame``
-===============================================================================
-
-You can add any extra attributes to the ``<iframe>`` tag using the new
-``extras`` argument in the ``IFrame`` class. For example::
-
-    In [1]: from IPython.display import IFrame
-
-    In [2]: IFrame(src="src", width=300, height=300, 
extras=['loading="eager"'])
-
-The above cells will result in the following HTML code being displayed in a
-notebook::
-
-    <iframe
-        width="300"
-        height="300"
-        src="src"
-        frameborder="0"
-        allowfullscreen
-        loading="eager"
-    ></iframe>
-
-Related to the above, the ``YouTubeVideo`` class now takes an
-``allow_autoplay`` flag, which sets up the iframe of the embedded YouTube video
-such that it allows autoplay.
-
-.. note::
-    Whether this works depends on the autoplay policy of the browser rendering
-    the HTML allowing it. It also could get blocked by some browser extensions.
-
-Try it out!
-::
-
-    In [1]: from IPython.display import YouTubeVideo
-
-    In [2]: YouTubeVideo("dQw4w9WgXcQ", allow_autoplay=True)
-
-????
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/ipython-7.28.0/docs/source/whatsnew/pr/pastebin-expiry-days.rst 
new/ipython-7.29.0/docs/source/whatsnew/pr/pastebin-expiry-days.rst
--- old/ipython-7.28.0/docs/source/whatsnew/pr/pastebin-expiry-days.rst 
2021-07-31 15:51:15.000000000 +0200
+++ new/ipython-7.29.0/docs/source/whatsnew/pr/pastebin-expiry-days.rst 
1970-01-01 01:00:00.000000000 +0100
@@ -1,7 +0,0 @@
-Pastebin magic expiry days option
-=================================
-
-The Pastebin magic now has ``-e`` option to determine 
-the number of days for paste expiration. For example
-the paste that created with ``%pastebin -e 20 1`` magic will
-be available for next 20 days.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/ipython-7.28.0/docs/source/whatsnew/version7.rst 
new/ipython-7.29.0/docs/source/whatsnew/version7.rst
--- old/ipython-7.28.0/docs/source/whatsnew/version7.rst        2021-09-25 
02:30:37.000000000 +0200
+++ new/ipython-7.29.0/docs/source/whatsnew/version7.rst        2021-10-30 
02:22:30.000000000 +0200
@@ -2,6 +2,48 @@
  7.x Series
 ============
 
+.. _version 7.29:
+
+IPython 7.29
+============
+
+
+IPython 7.29 brings a couple of new functionalities to IPython and a number of 
bugfixes.
+It is one of the largest recent release, relatively speaking, with close to 15 
Pull Requests.
+
+
+ - fix an issue where base64 was returned instead of bytes when showing 
figures :ghpull:`13162`
+ - fix compatibility with PyQt6, PySide 6 :ghpull:`13172`. This may be of
+   interest if you are running on Apple Silicon as only qt6.2+ is natively
+   compatible.
+ - fix matplotlib qtagg eventloop :ghpull:`13179`
+ - Multiple docs fixes, typos, ... etc.
+ - Debugger will now exit by default on SigInt :ghpull:`13218`, this will be
+   useful in notebook/lab if you forgot to exit the debugger. "Interrupt 
Kernel"
+   will now exist the debugger.
+
+It give Pdb the ability to skip code in decorators. If functions contain a
+special value names ``__debuggerskip__ = True|False``, the function will not be
+stepped into, and Pdb will step into lower frames only if the value is set to
+``False``. The exact behavior is still likely to have corner cases and will be
+refined in subsequent releases. Feedback welcome. See the debugger module
+documentation for more info. Thanks to the `D. E. Shaw
+group <https://deshaw.com/>`__ for funding this feature.
+
+The main branch of IPython is receiving a number of changes as we received a
+`NumFOCUS SDG <https://numfocus.org/programs/small-development-grants>`__
+($4800), to help us finish replacing ``nose`` by ``pytest``, and make IPython
+future proof with an 8.0 release.
+
+
+Many thanks to all the contributors to this release. You can find all 
individual
+contributions to this milestone `on github
+<https://github.com/ipython/ipython/milestone/93>`__.
+
+Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring
+work on IPython and related libraries.
+
+
 .. _version 7.28:
 
 IPython 7.28
@@ -38,6 +80,49 @@
  - Reword the YouTubeVideo autoplay WN :ghpull:`13147`
 
 
+Highlighted features
+--------------------
+
+
+``YouTubeVideo`` autoplay and the ability to add extra attributes to ``IFrame``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+You can add any extra attributes to the ``<iframe>`` tag using the new
+``extras`` argument in the ``IFrame`` class. For example::
+
+    In [1]: from IPython.display import IFrame
+
+    In [2]: IFrame(src="src", width=300, height=300, 
extras=['loading="eager"'])
+
+The above cells will result in the following HTML code being displayed in a
+notebook::
+
+    <iframe
+        width="300"
+        height="300"
+        src="src"
+        frameborder="0"
+        allowfullscreen
+        loading="eager"
+    ></iframe>
+
+Related to the above, the ``YouTubeVideo`` class now takes an
+``allow_autoplay`` flag, which sets up the iframe of the embedded YouTube video
+such that it allows autoplay.
+
+.. note::
+    Whether this works depends on the autoplay policy of the browser rendering
+    the HTML allowing it. It also could get blocked by some browser extensions.
+
+Try it out!
+::
+
+    In [1]: from IPython.display import YouTubeVideo
+
+    In [2]: YouTubeVideo("dQw4w9WgXcQ", allow_autoplay=True)
+
+
+
 Thanks
 ------
 
@@ -95,6 +180,16 @@
    :ghpull:`13056`
  - Make Ipython.utils.timing work with jupyterlite :ghpull:`13050`.
 
+Pastebin magic expiry days option
+---------------------------------
+
+The Pastebin magic now has ``-e`` option to determine 
+the number of days for paste expiration. For example
+the paste that created with ``%pastebin -e 20 1`` magic will
+be available for next 20 days.
+
+
+
 
 
 Thanks
@@ -543,7 +638,7 @@
 <https://pypi.org/project/frappuccino/>`_ (still in beta):
 
 
-The following items are new and mostly related to understanding 
``__tracebackbide__``::
+The following items are new and mostly related to understanding 
``__tracebackhide__``::
 
     + IPython.core.debugger.Pdb.do_down(self, arg)
     + IPython.core.debugger.Pdb.do_skip_hidden(self, arg)

Reply via email to