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

Reply via email to