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-12-25 20:16:32 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-ipython (Old) and /work/SRC/openSUSE:Factory/.python-ipython.new.2520 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-ipython" Sat Dec 25 20:16:32 2021 rev:25 rq:941688 version:7.30.1 Changes: -------- --- /work/SRC/openSUSE:Factory/python-ipython/python-ipython.changes 2021-11-15 15:27:43.309845703 +0100 +++ /work/SRC/openSUSE:Factory/.python-ipython.new.2520/python-ipython.changes 2021-12-25 20:16:42.825252931 +0100 @@ -1,0 +2,35 @@ +Mon Dec 20 18:35:45 UTC 2021 - Ben Greiner <c...@bnavigator.de> + +- Add patches for Python 3.10 + * ipython-pr13282-py310-inspect.patch -- gh#ipython/ipython#13282 + * ipython-pr13371-py310-oserror.patch -- gh#ipython/ipython#13371 + * gh#ipython/ipython#13412 + +------------------------------------------------------------------- +Sun Dec 19 19:24:08 UTC 2021 - Ben Greiner <c...@bnavigator.de> + +- Update to 7.30.1 + * IPython 7.30 fixes a couple of bugs introduce in previous + releases (in particular with respect to path handling), and + introduce a few features and improvements: + * Notably we will highlight PR #13267 ???Document that %run can + execute notebooks and ipy scripts.???, which is the first commit + of Fernando P??rez since mid 2016 (IPython 5.1). If you are new + to IPython, Fernando created IPython in 2001. The other most + recent contribution of Fernando to IPython itself was May 2018, + by reviewing and merging PRs. I want to note that Fernando is + still active but mostly as a mentor and leader of the whole + Jupyter organisation, but we???re still happy to see him + contribute code ! + * PR #13290 ???Use sphinxify (if available) in object_inspect_mime + path??? should allow richer Repr of docstrings when using + jupyterlab inspector. + * PR #13311 make the debugger use ThreadPoolExecutor for debugger + cmdloop. This should fix some issues/infinite loop, but let us + know if you come across any regressions. In particular this + fixes issues with kmaork/madbg, a remote debugger for IPython. + * Note that this is likely the ante-penultimate release of + IPython 7.x as a stable branch, as I hope to release IPython + 8.0 as well as IPython 7.31 next month/early 2022. + +------------------------------------------------------------------- Old: ---- ipython-7.29.0.tar.gz New: ---- ipython-7.30.1.tar.gz ipython-pr13282-py310-inspect.patch ipython-pr13371-py310-oserror.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-ipython.spec ++++++ --- /var/tmp/diff_new_pack.39FvmS/_old 2021-12-25 20:16:43.409253406 +0100 +++ /var/tmp/diff_new_pack.39FvmS/_new 2021-12-25 20:16:43.417253413 +0100 @@ -30,13 +30,13 @@ %define psuffix %{nil} %bcond_with test %endif -%{?!python_module:%define python_module() python-%{**} python3-%{**}} +%{?!python_module:%define python_module() python3-%{**}} %define skip_python2 1 # Python 3.6 was officiallay supported with IPython up to 7.15 %define skip_python36 1 %bcond_without iptest Name: python-ipython%{psuffix} -Version: 7.29.0 +Version: 7.30.1 Release: 0 Summary: Rich architecture for interactive computing with Python License: BSD-3-Clause @@ -44,6 +44,10 @@ URL: https://github.com/ipython/ipython Source: https://files.pythonhosted.org/packages/source/i/ipython/ipython-%{version}.tar.gz Source1: https://raw.githubusercontent.com/jupyter/qtconsole/4.0.0/qtconsole/resources/icon/JupyterConsole.svg +# PATCH-FIX-UPSTREAM ipython-pr13282-py310-inspect.patch -- gh#ipython/ipython#13282, gh#ipython/ipython#13412 +Patch0: ipython-pr13282-py310-inspect.patch +# PATCH-FIX-UPSTREAM ipython-pr13371-py310-oserror.patch -- gh#ipython/ipython#13371 +Patch1: ipython-pr13371-py310-oserror.patch BuildRequires: %{python_module backcall} BuildRequires: %{python_module base >= 3.7} BuildRequires: %{python_module setuptools >= 18.5} @@ -83,6 +87,7 @@ %if %{with test} # test requirements are specified in the iptest subpackage below BuildRequires: %{python_module ipython-iptest = %{version}} +BuildRequires: %{python_module testsuite} %endif %if !%{with test} BuildRequires: desktop-file-utils @@ -142,6 +147,9 @@ Requires: python-numpy >= 1.17 Requires: python-requests Requires: python-testpath +%if %{with libalternatives} +Requires: alts +%endif Provides: python-jupyter_ipython-iptest = %{version} Obsoletes: python-jupyter_ipython-iptest < %{version} @@ -150,7 +158,7 @@ testing software that uses %{name}. %prep -%setup -q -n ipython-%{version} +%autosetup -p1 -n ipython-%{version} %build %python_build @@ -202,8 +210,8 @@ %suse_update_desktop_file -i -r ipython-%{$python_bin_suffix} "System;TerminalEmulator;" } -# These can be run stand-alone, so make them executable rather than removing shebang -%{python_expand find %{buildroot}%{$python_sitelib} -type f -name "*.py" -exec sed -i "s|^#!%{_bindir}/env python$|#!%{__$python}|" {} \; +%{python_expand # These can be run stand-alone, so make them executable rather than removing shebang +find %{buildroot}%{$python_sitelib} -type f -name "*.py" -exec sed -i "s|^#!%{_bindir}/env python$|#!%{__$python}|" {} \; find %{buildroot}%{$python_sitelib} -type f -name "*.py" -exec sed -i "s|^#!%{_bindir}/python$|#!%{__$python}|" {} \; find %{buildroot}%{$python_sitelib} -type f -name "*.py" -exec grep -q "#!%{__$python}" {} \; -exec chmod a+x {} \; ++++++ ipython-7.29.0.tar.gz -> ipython-7.30.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/async_helpers.py new/ipython-7.30.1/IPython/core/async_helpers.py --- old/ipython-7.29.0/IPython/core/async_helpers.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/async_helpers.py 2021-12-02 18:21:27.000000000 +0100 @@ -13,19 +13,29 @@ import ast import sys +import asyncio import inspect from textwrap import dedent, indent class _AsyncIORunner: + def __init__(self): + self._loop = None + + @property + def loop(self): + """Always returns a non-closed event loop""" + if self._loop is None or self._loop.is_closed(): + policy = asyncio.get_event_loop_policy() + self._loop = policy.new_event_loop() + policy.set_event_loop(self._loop) + return self._loop def __call__(self, coro): """ Handler for asyncio autoawait """ - import asyncio - - return asyncio.get_event_loop().run_until_complete(coro) + return self.loop.run_until_complete(coro) def __str__(self): return 'asyncio' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/completer.py new/ipython-7.30.1/IPython/core/completer.py --- old/ipython-7.29.0/IPython/core/completer.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/completer.py 2021-12-02 18:21:27.000000000 +0100 @@ -166,7 +166,13 @@ # may have trouble processing. MATCHES_LIMIT = 500 -_deprecation_readline_sentinel = object() + +class Sentinel: + def __repr__(self): + return "<deprecated sentinel>" + + +_deprecation_readline_sentinel = Sentinel() class ProvisionalCompleterWarning(FutureWarning): @@ -1143,18 +1149,18 @@ if self.use_jedi: return [ *self.custom_matchers, + self.dict_key_matches, self.file_matches, self.magic_matches, - self.dict_key_matches, ] else: return [ *self.custom_matchers, + self.dict_key_matches, self.python_matches, self.file_matches, self.magic_matches, self.python_func_kw_matches, - self.dict_key_matches, ] def all_completions(self, text) -> List[str]: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/debugger.py new/ipython-7.30.1/IPython/core/debugger.py --- old/ipython-7.29.0/IPython/core/debugger.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/debugger.py 2021-12-02 18:21:27.000000000 +0100 @@ -415,9 +415,10 @@ if self._predicates["tbhide"]: if frame in (self.curframe, getattr(self, "initial_frame", None)): return False - else: - return self._get_frame_locals(frame).get("__tracebackhide__", False) - + frame_locals = self._get_frame_locals(frame) + if "__tracebackhide__" not in frame_locals: + return False + return frame_locals["__tracebackhide__"] return False def hidden_frames(self, stack): diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/interactiveshell.py new/ipython-7.30.1/IPython/core/interactiveshell.py --- old/ipython-7.29.0/IPython/core/interactiveshell.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/interactiveshell.py 2021-12-02 18:21:27.000000000 +0100 @@ -898,9 +898,7 @@ virtualenv was built, and it ignores the --no-site-packages option. A warning will appear suggesting the user installs IPython in the virtualenv, but for many cases, it probably works well enough. - Adapted from code snippets online. - http://blog.ufsoft.org/2009/1/29/ipython-and-virtualenv """ if 'VIRTUAL_ENV' not in os.environ: @@ -931,17 +929,27 @@ # Our exe is inside or has access to the virtualenv, don't need to do anything. return - warn("Attempting to work in a virtualenv. If you encounter problems, please " - "install IPython inside the virtualenv.") if sys.platform == "win32": - virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath( - "Lib", "site-packages" - ) + virtual_env = str(Path(os.environ["VIRTUAL_ENV"], "Lib", "site-packages")) else: - virtual_env = Path(os.environ["VIRTUAL_ENV"]).joinpath( - "lib", "python{}.{}".format(*sys.version_info[:2]), "site-packages" + virtual_env_path = Path( + os.environ["VIRTUAL_ENV"], "lib", "python{}.{}", "site-packages" ) - + p_ver = sys.version_info[:2] + + # Predict version from py[thon]-x.x in the $VIRTUAL_ENV + re_m = re.search(r"\bpy(?:thon)?([23])\.(\d+)\b", os.environ["VIRTUAL_ENV"]) + if re_m: + predicted_path = Path(str(virtual_env_path).format(*re_m.groups())) + if predicted_path.exists(): + p_ver = re_m.groups() + + virtual_env = str(virtual_env_path).format(*p_ver) + + warn( + "Attempting to work in a virtualenv. If you encounter problems, " + "please install IPython inside the virtualenv." + ) import site sys.path.insert(0, virtual_env) site.addsitedir(virtual_env) @@ -1804,8 +1812,13 @@ with self.builtin_trap: info = self._object_find(oname) if info.found: - return self.inspector._get_info(info.obj, oname, info=info, - detail_level=detail_level + docformat = sphinxify if self.sphinxify_docstring else None + return self.inspector._get_info( + info.obj, + oname, + info=info, + detail_level=detail_level, + formatter=docformat, ) else: raise KeyError(oname) @@ -2968,7 +2981,7 @@ result: bool Whether the code needs to be run with a coroutine runner or not - .. versionadded: 7.0 + .. versionadded:: 7.0 """ if not self.autoawait: return False @@ -3033,7 +3046,7 @@ ------- result : :class:`ExecutionResult` - .. versionadded: 7.0 + .. versionadded:: 7.0 """ info = ExecutionInfo( raw_cell, store_history, silent, shell_futures) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/magics/execution.py new/ipython-7.30.1/IPython/core/magics/execution.py --- old/ipython-7.29.0/IPython/core/magics/execution.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/magics/execution.py 2021-12-02 18:21:27.000000000 +0100 @@ -532,7 +532,18 @@ %run [-n -i -e -G] [( -t [-N<N>] | -d [-b<N>] | -p [profile options] )] - ( -m mod | file ) [args] + ( -m mod | filename ) [args] + + The filename argument should be either a pure Python script (with + extension ``.py``), or a file with custom IPython syntax (such as + magics). If the latter, the file can be either a script with ``.ipy`` + extension, or a Jupyter notebook with ``.ipynb`` extension. When running + a Jupyter notebook, the output from print statements and other + displayed objects will appear in the terminal (even matplotlib figures + will open, if a terminal-compliant backend is being used). Note that, + at the system command line, the ``jupyter run`` command offers similar + functionality for executing notebooks (albeit currently with some + differences in supported options). Parameters after the filename are passed as command-line arguments to the program (put in sys.argv). Then, control returns to IPython's diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/pylabtools.py new/ipython-7.30.1/IPython/core/pylabtools.py --- old/ipython-7.29.0/IPython/core/pylabtools.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/pylabtools.py 2021-12-02 18:21:27.000000000 +0100 @@ -119,7 +119,7 @@ If `base64` is True, return base64-encoded str instead of raw bytes for binary-encoded image formats - .. versionadded: 7.29 + .. versionadded:: 7.29 base64 argument """ # When there's an empty figure, we shouldn't return anything, otherwise we @@ -162,7 +162,7 @@ If `base64` is True, return base64-encoded str instead of raw bytes for binary-encoded image formats - .. versionadded: 7.29 + .. versionadded:: 7.29 base64 argument """ pngdata = print_figure(fig, fmt="retina", base64=False, **kwargs) @@ -399,7 +399,7 @@ def configure_inline_support(shell, backend): """ - .. deprecated: 7.23 + .. deprecated:: 7.23 use `matplotlib_inline.backend_inline.configure_inline_support()` diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/release.py new/ipython-7.30.1/IPython/core/release.py --- old/ipython-7.29.0/IPython/core/release.py 2021-10-30 02:52:42.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/release.py 2021-12-02 18:25:38.000000000 +0100 @@ -20,8 +20,8 @@ # release. 'dev' as a _version_extra string means this is a development # version _version_major = 7 -_version_minor = 29 -_version_patch = 0 +_version_minor = 30 +_version_patch = 1 _version_extra = '.dev' # _version_extra = 'b1' _version_extra = "" # Uncomment this for full releases diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/tests/test_inputsplitter.py new/ipython-7.30.1/IPython/core/tests/test_inputsplitter.py --- old/ipython-7.29.0/IPython/core/tests/test_inputsplitter.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/tests/test_inputsplitter.py 2021-12-02 18:21:27.000000000 +0100 @@ -14,6 +14,7 @@ from IPython.core.inputtransformer import InputTransformer from IPython.core.tests.test_inputtransformer import syntax, syntax_ml from IPython.testing import tools as tt +from IPython.testing.decorators import skipif #----------------------------------------------------------------------------- # Semi-complete examples (also used as tests) @@ -323,6 +324,7 @@ self.isp.push(u'\xc3\xa9') self.isp.push(u"u'\xc3\xa9'") + @skipif(sys.version_info[:3] == (3, 9, 8)) def test_line_continuation(self): """ Test issue #2108.""" isp = self.isp diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/tests/test_inputtransformer2.py new/ipython-7.30.1/IPython/core/tests/test_inputtransformer2.py --- old/ipython-7.29.0/IPython/core/tests/test_inputtransformer2.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/tests/test_inputtransformer2.py 2021-12-02 18:21:27.000000000 +0100 @@ -6,11 +6,14 @@ """ import nose.tools as nt import string +import sys +from textwrap import dedent -from IPython.core import inputtransformer2 as ipt2 -from IPython.core.inputtransformer2 import make_tokens_by_line, _find_assign_op +import pytest -from textwrap import dedent +from IPython.core import inputtransformer2 as ipt2 +from IPython.core.inputtransformer2 import _find_assign_op, make_tokens_by_line +from IPython.testing.decorators import skip MULTILINE_MAGIC = ("""\ a = f() @@ -253,20 +256,38 @@ nt.assert_equal(_find_assign_op([Tk(s) for s in ('','a','=','b')]), 2) nt.assert_equal(_find_assign_op([Tk(s) for s in ('','(', 'a','=','b', ')', '=' ,'5')]), 6) +examples = [ + pytest.param("a = 1", "complete", None), + pytest.param("for a in range(5):", "incomplete", 4), + pytest.param("for a in range(5):\n if a > 0:", "incomplete", 8), + pytest.param("raise = 2", "invalid", None), + pytest.param("a = [1,\n2,", "incomplete", 0), + pytest.param("(\n))", "incomplete", 0), + pytest.param("\\\r\n", "incomplete", 0), + pytest.param("a = '''\n hi", "incomplete", 3), + pytest.param("def a():\n x=1\n global x", "invalid", None), + pytest.param( + "a \\ ", + "invalid", + None, + marks=pytest.mark.xfail( + reason="Bug in python 3.9.8 ?????bpo 45738", + condition=sys.version_info[:3] == (3, 9, 8), + raises=SystemError, + strict=True, + ), + ), # Nothing allowed after backslash, + pytest.param("1\\\n+2", "complete", None), +] + + +@skip('Tested on master, skip only on iptest not available on 7.x') +@pytest.mark.xfail( + reason="Bug in python 3.9.8 ?????bpo 45738", + condition=sys.version_info[:3] == (3, 9, 8), +) def test_check_complete(): cc = ipt2.TransformerManager().check_complete - nt.assert_equal(cc("a = 1"), ('complete', None)) - nt.assert_equal(cc("for a in range(5):"), ('incomplete', 4)) - nt.assert_equal(cc("for a in range(5):\n if a > 0:"), ('incomplete', 8)) - nt.assert_equal(cc("raise = 2"), ('invalid', None)) - nt.assert_equal(cc("a = [1,\n2,"), ('incomplete', 0)) - nt.assert_equal(cc(")"), ('incomplete', 0)) - nt.assert_equal(cc("\\\r\n"), ('incomplete', 0)) - nt.assert_equal(cc("a = '''\n hi"), ('incomplete', 3)) - nt.assert_equal(cc("def a():\n x=1\n global x"), ('invalid', None)) - nt.assert_equal(cc("a \\ "), ('invalid', None)) # Nothing allowed after backslash - nt.assert_equal(cc("1\\\n+2"), ('complete', None)) - nt.assert_equal(cc("exit"), ('complete', None)) example = dedent(""" if True: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/core/tests/test_interactiveshell.py new/ipython-7.30.1/IPython/core/tests/test_interactiveshell.py --- old/ipython-7.29.0/IPython/core/tests/test_interactiveshell.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/core/tests/test_interactiveshell.py 2021-12-02 18:21:27.000000000 +0100 @@ -1037,6 +1037,22 @@ assert result.result == 5 +def test_run_cell_await(): + ip.run_cell("import asyncio") + result = ip.run_cell("await asyncio.sleep(0.01); 10") + assert ip.user_ns["_"] == 10 + + +def test_run_cell_asyncio_run(): + ip.run_cell("import asyncio") + result = ip.run_cell("await asyncio.sleep(0.01); 1") + assert ip.user_ns["_"] == 1 + result = ip.run_cell("asyncio.run(asyncio.sleep(0.01)); 2") + assert ip.user_ns["_"] == 2 + result = ip.run_cell("await asyncio.sleep(0.01); 3") + assert ip.user_ns["_"] == 3 + + def test_should_run_async(): assert not ip.should_run_async("a = 5") assert ip.should_run_async("await x") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/paths.py new/ipython-7.30.1/IPython/paths.py --- old/ipython-7.29.0/IPython/paths.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/paths.py 2021-12-02 18:21:27.000000000 +0100 @@ -67,7 +67,7 @@ " using a temp directory.".format(parent)) ipdir = tempfile.mkdtemp() else: - os.makedirs(ipdir) + os.makedirs(ipdir, exist_ok=True) 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.29.0/IPython/terminal/debugger.py new/ipython-7.30.1/IPython/terminal/debugger.py --- old/ipython-7.29.0/IPython/terminal/debugger.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/terminal/debugger.py 2021-12-02 18:21:27.000000000 +0100 @@ -1,10 +1,8 @@ import asyncio import signal import sys -import threading from IPython.core.debugger import Pdb - from IPython.core.completer import IPCompleter from .ptutils import IPythonPTCompleter from .shortcuts import create_ipython_shortcuts, suspend_to_bg, cursor_in_leading_ws @@ -18,6 +16,7 @@ from prompt_toolkit.shortcuts.prompt import PromptSession from prompt_toolkit.enums import EditingMode from prompt_toolkit.formatted_text import PygmentsTokens +from concurrent.futures import ThreadPoolExecutor from prompt_toolkit import __version__ as ptk_version PTK3 = ptk_version.startswith('3.') @@ -30,6 +29,7 @@ Pdb.__init__(self, *args, **kwargs) self._ptcomp = None self.pt_init(pt_session_options) + self.thread_executor = ThreadPoolExecutor(1) def pt_init(self, pt_session_options=None): """Initialize the prompt session and the prompt loop @@ -102,7 +102,7 @@ if intro is not None: self.intro = intro if self.intro: - self.stdout.write(str(self.intro)+"\n") + print(self.intro, file=self.stdout) stop = None while not stop: if self.cmdqueue: @@ -112,24 +112,11 @@ self._ptcomp.ipy_completer.global_namespace = self.curframe.f_globals # Run the prompt in a different thread. - line = '' - keyboard_interrupt = False - - def in_thread(): - nonlocal line, keyboard_interrupt - try: - line = self.pt_app.prompt() - except EOFError: - line = 'EOF' - except KeyboardInterrupt: - keyboard_interrupt = True - - th = threading.Thread(target=in_thread) - th.start() - th.join() + try: + line = self.thread_executor.submit(self.pt_app.prompt).result() + except EOFError: + line = "EOF" - 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.29.0/IPython/terminal/interactiveshell.py new/ipython-7.30.1/IPython/terminal/interactiveshell.py --- old/ipython-7.29.0/IPython/terminal/interactiveshell.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/terminal/interactiveshell.py 2021-12-02 18:21:27.000000000 +0100 @@ -460,13 +460,15 @@ # If we don't do this, people could spawn coroutine with a # while/true inside which will freeze the prompt. + policy = asyncio.get_event_loop_policy() try: - old_loop = asyncio.get_event_loop() + old_loop = policy.get_event_loop() except RuntimeError: - # This happens when the user used `asyncio.run()`. + # This happens when the the event loop is closed, + # e.g. by calling `asyncio.run()`. old_loop = None - asyncio.set_event_loop(self.pt_loop) + policy.set_event_loop(self.pt_loop) try: with patch_stdout(raw=True): text = self.pt_app.prompt( @@ -474,7 +476,8 @@ **self._extra_prompt_options()) finally: # Restore the original event loop. - asyncio.set_event_loop(old_loop) + if old_loop is not None: + policy.set_event_loop(old_loop) return text diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/utils/_sysinfo.py new/ipython-7.30.1/IPython/utils/_sysinfo.py --- old/ipython-7.29.0/IPython/utils/_sysinfo.py 2021-10-30 02:52:42.000000000 +0200 +++ new/ipython-7.30.1/IPython/utils/_sysinfo.py 2021-12-02 18:25:38.000000000 +0100 @@ -1,2 +1,2 @@ # GENERATED BY setup.py -commit = u"3813660de" +commit = u"44cd8b1e6" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/IPython/utils/text.py new/ipython-7.30.1/IPython/utils/text.py --- old/ipython-7.29.0/IPython/utils/text.py 2021-10-30 02:22:27.000000000 +0200 +++ new/ipython-7.30.1/IPython/utils/text.py 2021-12-02 18:21:27.000000000 +0100 @@ -597,6 +597,9 @@ # Re-yield the {foo} style pattern yield (txt + literal_txt[continue_from:], field_name, format_spec, conversion) + def __repr__(self): + return "<DollarFormatter>" + #----------------------------------------------------------------------------- # Utils to columnize a list of string #----------------------------------------------------------------------------- diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/ipython-7.29.0/PKG-INFO new/ipython-7.30.1/PKG-INFO --- old/ipython-7.29.0/PKG-INFO 2021-10-30 02:52:42.000000000 +0200 +++ new/ipython-7.30.1/PKG-INFO 2021-12-02 18:25:38.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 1.1 Name: ipython -Version: 7.29.0 +Version: 7.30.1 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.29.0/docs/source/whatsnew/version7.rst new/ipython-7.30.1/docs/source/whatsnew/version7.rst --- old/ipython-7.29.0/docs/source/whatsnew/version7.rst 2021-10-30 02:22:30.000000000 +0200 +++ new/ipython-7.30.1/docs/source/whatsnew/version7.rst 2021-12-02 01:31:11.000000000 +0100 @@ -2,6 +2,51 @@ 7.x Series ============ +.. _version 7.30: + +IPython 7.30 +============ + +IPython 7.30 fixes a couple of bugs introduce in previous releases (in +particular with respect to path handling), and introduce a few features and +improvements: + +Notably we will highlight :ghpull:`13267` "Document that ``%run`` can execute +notebooks and ipy scripts.", which is the first commit of Fernando P??rez since +mid 2016 (IPython 5.1). If you are new to IPython, Fernando created IPython in +2001. The other most recent contribution of Fernando to IPython itself was +May 2018, by reviewing and merging PRs. I want to note that Fernando is still +active but mostly as a mentor and leader of the whole Jupyter organisation, but +we're still happy to see him contribute code ! + +:ghpull:`13290` "Use sphinxify (if available) in object_inspect_mime path" +should allow richer Repr of docstrings when using jupyterlab inspector. + +:ghpull:`13311` make the debugger use ``ThreadPoolExecutor`` for debugger cmdloop. +This should fix some issues/infinite loop, but let us know if you come across +any regressions. In particular this fixes issues with `kmaork/madbg <https://github.com/kmaork/madbg>`_, +a remote debugger for IPython. + +Note that this is likely the ante-penultimate release of IPython 7.x as a stable +branch, as I hope to release IPython 8.0 as well as IPython 7.31 next +month/early 2022. + +IPython 8.0 will drop support for Python 3.7, removed nose as a dependency, and +7.x will only get critical bug fixes with 8.x becoming the new stable. This will +not be possible without `NumFOCUS Small Development Grants +<https://numfocus.org/programs/small-development-grants>`_ Which allowed us to +hire `Nikita Kniazev <https://github.com/Kojoley>`_ who provide Python and C++ +help and contracting work. + + +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/94?closed=1>`__. + +Thanks as well to the `D. E. Shaw group <https://deshaw.com/>`__ for sponsoring +work on IPython and related libraries. + + .. _version 7.29: IPython 7.29 @@ -596,6 +641,19 @@ .. _version 716: +IPython 7.16.1, 7.16.2 +====================== + +IPython 7.16.1 was release immediately after 7.16.0 to fix a conda packaging issue. +The source is identical to 7.16.0 but the file permissions in the tar are different. + +IPython 7.16.2 pins jedi dependency to "<=0.17.2" which should prevent some +issues for users still on python 3.6. This may not be sufficient as pip may +still allow to downgrade IPython. + +Compatibility with Jedi > 0.17.2 was not added as this would have meant bumping +the minimal version to >0.16. + IPython 7.16 ============ ++++++ ipython-pr13282-py310-inspect.patch ++++++ >From fc57ec912eec9da4c33d8db5416fdb2dada706e7 Mon Sep 17 00:00:00 2001 From: Nikita Kniazev <nok.ra...@gmail.com> Date: Mon, 1 Nov 2021 19:09:58 +0300 Subject: [PATCH 1/5] Handle changed exception type from inspect.getabsfile (bpo-44648) https://bugs.python.org/issue44648 (Python 3.10+) --- IPython/core/oinspect.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) Index: ipython-7.30.1/IPython/core/oinspect.py =================================================================== --- ipython-7.30.1.orig/IPython/core/oinspect.py +++ ipython-7.30.1/IPython/core/oinspect.py @@ -305,13 +305,13 @@ def find_file(obj) -> str: fname = None try: fname = inspect.getabsfile(obj) - except TypeError: + except (OSError, TypeError): # For an instance, the file that matters is where its class was # declared. if hasattr(obj, '__class__'): try: fname = inspect.getabsfile(obj.__class__) - except TypeError: + except (OSError, TypeError): # Can happen for builtins pass except: Index: ipython-7.30.1/IPython/core/tests/test_magic_arguments.py =================================================================== --- ipython-7.30.1.orig/IPython/core/tests/test_magic_arguments.py +++ ipython-7.30.1/IPython/core/tests/test_magic_arguments.py @@ -7,6 +7,7 @@ #----------------------------------------------------------------------------- import argparse +import sys from nose.tools import assert_equal from IPython.core.magic_arguments import (argument, argument_group, kwds, @@ -74,7 +75,12 @@ def foo(self, args): def test_magic_arguments(): - assert_equal(magic_foo1.__doc__, '::\n\n %foo1 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n') + # ???optional arguments??? was replaced with ???options??? in argparse help + # https://docs.python.org/3/whatsnew/3.10.html#argparse + # https://bugs.python.org/issue9694 + options = "optional arguments" if sys.version_info < (3, 10) else "options" + + assert_equal(magic_foo1.__doc__, f"::\n\n %foo1 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n") assert_equal(getattr(magic_foo1, 'argcmd_name', None), None) assert_equal(real_name(magic_foo1), 'foo1') assert_equal(magic_foo1(None, ''), argparse.Namespace(foo=None)) @@ -86,32 +92,32 @@ def test_magic_arguments(): assert_equal(magic_foo2(None, ''), argparse.Namespace()) assert hasattr(magic_foo2, 'has_arguments') - assert_equal(magic_foo3.__doc__, '::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n') + assert_equal(magic_foo3.__doc__, f"::\n\n %foo3 [-f FOO] [-b BAR] [-z BAZ]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n\nGroup:\n -b BAR, --bar BAR a grouped argument\n\nSecond Group:\n -z BAZ, --baz BAZ another grouped argument\n") assert_equal(getattr(magic_foo3, 'argcmd_name', None), None) assert_equal(real_name(magic_foo3), 'foo3') assert_equal(magic_foo3(None, ''), argparse.Namespace(bar=None, baz=None, foo=None)) assert hasattr(magic_foo3, 'has_arguments') - assert_equal(magic_foo4.__doc__, '::\n\n %foo4 [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n') + assert_equal(magic_foo4.__doc__, f"::\n\n %foo4 [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n") assert_equal(getattr(magic_foo4, 'argcmd_name', None), None) assert_equal(real_name(magic_foo4), 'foo4') assert_equal(magic_foo4(None, ''), argparse.Namespace()) assert hasattr(magic_foo4, 'has_arguments') - assert_equal(magic_foo5.__doc__, '::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n') + assert_equal(magic_foo5.__doc__, f"::\n\n %frobnicate [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n") assert_equal(getattr(magic_foo5, 'argcmd_name', None), 'frobnicate') assert_equal(real_name(magic_foo5), 'frobnicate') assert_equal(magic_foo5(None, ''), argparse.Namespace(foo=None)) assert hasattr(magic_foo5, 'has_arguments') - assert_equal(magic_magic_foo.__doc__, '::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n') + assert_equal(magic_magic_foo.__doc__, f"::\n\n %magic_foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n") assert_equal(getattr(magic_magic_foo, 'argcmd_name', None), None) assert_equal(real_name(magic_magic_foo), 'magic_foo') assert_equal(magic_magic_foo(None, ''), argparse.Namespace(foo=None)) assert hasattr(magic_magic_foo, 'has_arguments') - assert_equal(foo.__doc__, '::\n\n %foo [-f FOO]\n\n A docstring.\n\noptional arguments:\n -f FOO, --foo FOO an argument\n') + assert_equal(foo.__doc__, f"::\n\n %foo [-f FOO]\n\n A docstring.\n\n{options}:\n -f FOO, --foo FOO an argument\n") assert_equal(getattr(foo, 'argcmd_name', None), None) assert_equal(real_name(foo), 'foo') assert_equal(foo(None, ''), argparse.Namespace(foo=None)) Index: ipython-7.30.1/IPython/core/tests/test_completer.py =================================================================== --- ipython-7.30.1.orig/IPython/core/tests/test_completer.py +++ ipython-7.30.1/IPython/core/tests/test_completer.py @@ -12,6 +12,7 @@ import unittest from contextlib import contextmanager import nose.tools as nt +import pytest from traitlets.config.loader import Config from IPython import get_ipython @@ -29,6 +30,15 @@ from IPython.core.completer import ( ) from nose.tools import assert_in, assert_not_in +if sys.version_info >= (3, 10): + import jedi + from pkg_resources import parse_version + + # Requires https://github.com/davidhalter/jedi/pull/1795 + jedi_issue = parse_version(jedi.__version__) <= parse_version("0.18.0") +else: + jedi_issue = False + # ----------------------------------------------------------------------------- # Test functions # ----------------------------------------------------------------------------- @@ -381,6 +391,8 @@ class TestCompleter(unittest.TestCase): matches = c.all_completions("TestCl") assert matches == ['TestClass'], jedi_status matches = c.all_completions("TestClass.") + if jedi_status and jedi_issue: + continue assert len(matches) > 2, jedi_status matches = c.all_completions("TestClass.a") assert matches == ['TestClass.a', 'TestClass.a1'], jedi_status @@ -435,6 +447,7 @@ class TestCompleter(unittest.TestCase): "encoding" in c.signature ), "Signature of function was not found by completer" + @pytest.mark.xfail(jedi_issue, reason="Known failure on jedi<=0.18.0") def test_deduplicate_completions(self): """ Test that completions are correctly deduplicated (even if ranges are not the same) Index: ipython-7.30.1/IPython/lib/tests/test_pretty.py =================================================================== --- ipython-7.30.1.orig/IPython/lib/tests/test_pretty.py +++ ipython-7.30.1/IPython/lib/tests/test_pretty.py @@ -7,14 +7,15 @@ from collections import Counter, defaultdict, deque, OrderedDict import os +import pytest import types import string +import sys import unittest import nose.tools as nt from IPython.lib import pretty -from IPython.testing.decorators import skip_without from io import StringIO @@ -118,12 +119,12 @@ def test_sets(): yield nt.assert_equal, got_output, expected_output -@skip_without('xxlimited') def test_pprint_heap_allocated_type(): """ Test that pprint works for heap allocated types. """ - import xxlimited + module_name = "xxlimited" if sys.version_info < (3, 10) else "xxlimited_35" + xxlimited = pytest.importorskip(module_name) output = pretty.pretty(xxlimited.Null) nt.assert_equal(output, 'xxlimited.Null') ++++++ ipython-pr13371-py310-oserror.patch ++++++ >From aa169302f4acbbcae616154bf54c70167dbd1fd5 Mon Sep 17 00:00:00 2001 From: Nikita Kniazev <nok.ra...@gmail.com> Date: Sat, 4 Dec 2021 19:32:13 +0300 Subject: [PATCH 1/2] Everything is an object and has a `__class__` in Python 3 --- IPython/core/oinspect.py | 27 +++++++++++---------------- 1 file changed, 11 insertions(+), 16 deletions(-) Index: ipython-7.30.1/IPython/core/oinspect.py =================================================================== --- ipython-7.30.1.orig/IPython/core/oinspect.py +++ ipython-7.30.1/IPython/core/oinspect.py @@ -182,11 +182,12 @@ def getsource(obj, oname='') -> Union[st except TypeError: # The object itself provided no meaningful source, try looking for # its class definition instead. - if hasattr(obj, '__class__'): - try: - src = inspect.getsource(obj.__class__) - except TypeError: - return None + try: + src = inspect.getsource(obj.__class__) + except (OSError, TypeError): + return None + except OSError: + return None return src @@ -305,17 +306,17 @@ def find_file(obj) -> str: fname = None try: fname = inspect.getabsfile(obj) - except (OSError, TypeError): + except TypeError: # For an instance, the file that matters is where its class was # declared. - if hasattr(obj, '__class__'): - try: - fname = inspect.getabsfile(obj.__class__) - except (OSError, TypeError): - # Can happen for builtins - pass - except: + try: + fname = inspect.getabsfile(obj.__class__) + except (OSError, TypeError): + # Can happen for builtins + pass + except OSError: pass + return cast_unicode(fname) @@ -338,15 +339,14 @@ def find_source_lines(obj): obj = _get_wrapped(obj) try: + lineno = inspect.getsourcelines(obj)[1] + except TypeError: + # For instances, try the class object like getsource() does try: - lineno = inspect.getsourcelines(obj)[1] - except TypeError: - # For instances, try the class object like getsource() does - if hasattr(obj, '__class__'): - lineno = inspect.getsourcelines(obj.__class__)[1] - else: - lineno = None - except: + lineno = inspect.getsourcelines(obj.__class__)[1] + except (OSError, TypeError): + return None + except OSError: return None return lineno Index: ipython-7.30.1/IPython/core/tests/test_oinspect.py =================================================================== --- ipython-7.30.1.orig/IPython/core/tests/test_oinspect.py +++ ipython-7.30.1/IPython/core/tests/test_oinspect.py @@ -6,10 +6,11 @@ from inspect import signature, Signature, Parameter +import inspect import os +import pytest import re - -import nose.tools as nt +import sys from .. import oinspect @@ -30,6 +31,10 @@ def setup_module(): inspector = oinspect.Inspector() +class SourceModuleMainTest: + __module__ = "__main__" + + #----------------------------------------------------------------------------- # Local utilities #----------------------------------------------------------------------------- @@ -38,15 +43,28 @@ def setup_module(): # defined, if any code is inserted above, the following line will need to be # updated. Do NOT insert any whitespace between the next line and the function # definition below. -THIS_LINE_NUMBER = 41 # Put here the actual number of this line +THIS_LINE_NUMBER = 46 # Put here the actual number of this line + -from unittest import TestCase +def test_find_source_lines(): + assert oinspect.find_source_lines(test_find_source_lines) == THIS_LINE_NUMBER + 3 + assert oinspect.find_source_lines(type) is None + assert oinspect.find_source_lines(SourceModuleMainTest) is None + assert oinspect.find_source_lines(SourceModuleMainTest()) is None -class Test(TestCase): - def test_find_source_lines(self): - self.assertEqual(oinspect.find_source_lines(Test.test_find_source_lines), - THIS_LINE_NUMBER+6) +def test_getsource(): + assert oinspect.getsource(type) is None + assert oinspect.getsource(SourceModuleMainTest) is None + assert oinspect.getsource(SourceModuleMainTest()) is None + + +def test_inspect_getfile_raises_exception(): + """Check oinspect.find_file/getsource/find_source_lines expectations""" + with pytest.raises(TypeError): + inspect.getfile(type) + with pytest.raises(OSError if sys.version_info >= (3, 10) else TypeError): + inspect.getfile(SourceModuleMainTest) # A couple of utilities to ensure these tests work the same from a source or a @@ -56,11 +74,14 @@ def pyfile(fname): def match_pyfiles(f1, f2): - nt.assert_equal(pyfile(f1), pyfile(f2)) + assert pyfile(f1) == pyfile(f2) def test_find_file(): match_pyfiles(oinspect.find_file(test_find_file), os.path.abspath(__file__)) + assert oinspect.find_file(type) is None + assert oinspect.find_file(SourceModuleMainTest) is None + assert oinspect.find_file(SourceModuleMainTest()) is None def test_find_file_decorated1(): @@ -74,9 +95,9 @@ def test_find_file_decorated1(): @noop1 def f(x): "My docstring" - + match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) - nt.assert_equal(f.__doc__, "My docstring") + assert f.__doc__ == "My docstring" def test_find_file_decorated2(): @@ -90,14 +111,14 @@ def test_find_file_decorated2(): @noop2 def f(x): "My docstring 2" - + match_pyfiles(oinspect.find_file(f), os.path.abspath(__file__)) - nt.assert_equal(f.__doc__, "My docstring 2") - + assert f.__doc__ == "My docstring 2" + def test_find_file_magic(): run = ip.find_line_magic('run') - nt.assert_not_equal(oinspect.find_file(run), None) + assert oinspect.find_file(run) is not None # A few generic objects we can then inspect in the tests below @@ -167,41 +188,46 @@ class SerialLiar(object): def test_info(): "Check that Inspector.info fills out various fields as expected." - i = inspector.info(Call, oname='Call') - nt.assert_equal(i['type_name'], 'type') - expted_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'> - nt.assert_equal(i['base_class'], expted_class) - nt.assert_regex(i['string_form'], "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>") + i = inspector.info(Call, oname="Call") + assert i["type_name"] == "type" + expected_class = str(type(type)) # <class 'type'> (Python 3) or <type 'type'> + assert i["base_class"] == expected_class + assert re.search( + "<class 'IPython.core.tests.test_oinspect.Call'( at 0x[0-9a-f]{1,9})?>", + i["string_form"], + ) fname = __file__ if fname.endswith(".pyc"): fname = fname[:-1] # case-insensitive comparison needed on some filesystems # e.g. Windows: - nt.assert_equal(i['file'].lower(), compress_user(fname).lower()) - nt.assert_equal(i['definition'], None) - nt.assert_equal(i['docstring'], Call.__doc__) - nt.assert_equal(i['source'], None) - nt.assert_true(i['isclass']) - nt.assert_equal(i['init_definition'], "Call(x, y=1)") - nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) + assert i["file"].lower() == compress_user(fname).lower() + assert i["definition"] == None + assert i["docstring"] == Call.__doc__ + assert i["source"] == None + assert i["isclass"] is True + assert i["init_definition"] == "Call(x, y=1)" + assert i["init_docstring"] == Call.__init__.__doc__ i = inspector.info(Call, detail_level=1) - nt.assert_not_equal(i['source'], None) - nt.assert_equal(i['docstring'], None) + assert i["source"] is not None + assert i["docstring"] == None c = Call(1) c.__doc__ = "Modified instance docstring" i = inspector.info(c) - nt.assert_equal(i['type_name'], 'Call') - nt.assert_equal(i['docstring'], "Modified instance docstring") - nt.assert_equal(i['class_docstring'], Call.__doc__) - nt.assert_equal(i['init_docstring'], Call.__init__.__doc__) - nt.assert_equal(i['call_docstring'], Call.__call__.__doc__) + assert i["type_name"] == "Call" + assert i["docstring"] == "Modified instance docstring" + assert i["class_docstring"] == Call.__doc__ + assert i["init_docstring"] == Call.__init__.__doc__ + assert i["call_docstring"] == Call.__call__.__doc__ + def test_class_signature(): - info = inspector.info(HasSignature, 'HasSignature') - nt.assert_equal(info['init_definition'], "HasSignature(test)") - nt.assert_equal(info['init_docstring'], HasSignature.__init__.__doc__) + info = inspector.info(HasSignature, "HasSignature") + assert info["init_definition"] == "HasSignature(test)" + assert info["init_docstring"] == HasSignature.__init__.__doc__ + def test_info_awkward(): # Just test that this doesn't throw an error. @@ -216,7 +242,7 @@ def test_info_serialliar(): # Nested attribute access should be cut off at 100 levels deep to avoid # infinite loops: https://github.com/ipython/ipython/issues/9122 - nt.assert_less(fib_tracker[0], 9000) + assert fib_tracker[0] < 9000 def support_function_one(x, y=2, *a, **kw): """A simple function.""" @@ -225,14 +251,16 @@ def test_calldef_none(): # We should ignore __call__ for all of these. for obj in [support_function_one, SimpleClass().method, any, str.upper]: i = inspector.info(obj) - nt.assert_is(i['call_def'], None) + assert i["call_def"] is None + def f_kwarg(pos, *, kwonly): pass def test_definition_kwonlyargs(): - i = inspector.info(f_kwarg, oname='f_kwarg') # analysis:ignore - nt.assert_equal(i['definition'], "f_kwarg(pos, *, kwonly)") + i = inspector.info(f_kwarg, oname="f_kwarg") # analysis:ignore + assert i["definition"] == "f_kwarg(pos, *, kwonly)" + def test_getdoc(): class A(object): @@ -243,34 +271,33 @@ def test_getdoc(): """standard docstring""" def getdoc(self): return "custom docstring" - + class C(object): """standard docstring""" def getdoc(self): return None - + a = A() b = B() c = C() - - nt.assert_equal(oinspect.getdoc(a), "standard docstring") - nt.assert_equal(oinspect.getdoc(b), "custom docstring") - nt.assert_equal(oinspect.getdoc(c), "standard docstring") + + assert oinspect.getdoc(a) == "standard docstring" + assert oinspect.getdoc(b) == "custom docstring" + assert oinspect.getdoc(c) == "standard docstring" def test_empty_property_has_no_source(): i = inspector.info(property(), detail_level=1) - nt.assert_is(i['source'], None) + assert i["source"] is None def test_property_sources(): - import posixpath # A simple adder whose source and signature stays # the same across Python distributions def simple_add(a, b): "Adds two numbers" return a + b - + class A(object): @property def foo(self): @@ -278,18 +305,18 @@ def test_property_sources(): foo = foo.setter(lambda self, v: setattr(self, 'bar', v)) - dname = property(posixpath.dirname) - adder = property(simple_add) + dname = property(oinspect.getdoc) + adder = property(simple_add) i = inspector.info(A.foo, detail_level=1) - nt.assert_in('def foo(self):', i['source']) - nt.assert_in('lambda self, v:', i['source']) + assert "def foo(self):" in i["source"] + assert "lambda self, v:" in i["source"] i = inspector.info(A.dname, detail_level=1) - nt.assert_in('def dirname(p)', i['source']) - + assert "def getdoc(obj)" in i["source"] + i = inspector.info(A.adder, detail_level=1) - nt.assert_in('def simple_add(a, b)', i['source']) + assert "def simple_add(a, b)" in i["source"] def test_property_docstring_is_in_info_for_detail_level_0(): @@ -299,15 +326,17 @@ def test_property_docstring_is_in_info_f """This is `foobar` property.""" pass - ip.user_ns['a_obj'] = A() - nt.assert_equal( - 'This is `foobar` property.', - ip.object_inspect('a_obj.foobar', detail_level=0)['docstring']) - - ip.user_ns['a_cls'] = A - nt.assert_equal( - 'This is `foobar` property.', - ip.object_inspect('a_cls.foobar', detail_level=0)['docstring']) + ip.user_ns["a_obj"] = A() + assert ( + "This is `foobar` property." + == ip.object_inspect("a_obj.foobar", detail_level=0)["docstring"] + ) + + ip.user_ns["a_cls"] = A + assert ( + "This is `foobar` property." + == ip.object_inspect("a_cls.foobar", detail_level=0)["docstring"] + ) def test_pdef(): @@ -359,11 +388,11 @@ def test_pinfo_docstring_if_detail_and_n def bar(self): """ This is a docstring for Foo.bar """ pass - ''' - + ''' + ip.run_cell(obj_def) ip.run_cell('foo = Foo()') - + with AssertNotPrints("Source:"): with AssertPrints('Docstring:'): ip._inspect('pinfo', 'foo', detail_level=0) @@ -388,14 +417,14 @@ def test_pinfo_magic(): def test_init_colors(): # ensure colors are not present in signature info info = inspector.info(HasSignature) - init_def = info['init_definition'] - nt.assert_not_in('[0m', init_def) + init_def = info["init_definition"] + assert "[0m" not in init_def def test_builtin_init(): info = inspector.info(list) init_def = info['init_definition'] - nt.assert_is_not_none(init_def) + assert init_def is not None def test_render_signature_short(): @@ -404,7 +433,7 @@ def test_render_signature_short(): signature(short_fun), short_fun.__name__, ) - nt.assert_equal(sig, 'short_fun(a=1)') + assert sig == "short_fun(a=1)" def test_render_signature_long(): @@ -420,7 +449,7 @@ def test_render_signature_long(): signature(long_function), long_function.__name__, ) - nt.assert_in(sig, [ + assert sig in [ # Python >=3.9 '''\ long_function( @@ -444,4 +473,4 @@ long_function( let_us_make_sure_this_is_looong:Union[str, NoneType]=None, ) -> bool\ ''', - ]) + ] \ No newline at end of file