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)