From 56c8a1e6f82ea7032ff8435cee3c5b3c9ab00b56 2022-10-17 07:05:00 From: Matthias Bussonnier Date: 2022-10-17 07:05:00 Subject: [PATCH] support negative indexing --- diff --git a/IPython/core/inputtransformer2.py b/IPython/core/inputtransformer2.py index 432e091..37f0e76 100644 --- a/IPython/core/inputtransformer2.py +++ b/IPython/core/inputtransformer2.py @@ -432,12 +432,14 @@ class EscapedCommand(TokenTransformBase): _help_end_re = re.compile( r"""(%{0,2} - (?!\d)[\w*]+ # Variable name - (\.(?!\d)[\w*]+|\[[0-9]+\])* # .etc.etc or [0], we only support literal integers. - ) - (\?\??)$ # ? or ?? - """, - re.VERBOSE) + (?!\d)[\w*]+ # Variable name + (\.(?!\d)[\w*]+|\[-?[0-9]+\])* # .etc.etc or [0], we only support literal integers. + ) + (\?\??)$ # ? or ?? + """, + re.VERBOSE, +) + class HelpEnd(TokenTransformBase): """Transformer for help syntax: obj? and obj??""" diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 9b3cc06..04094d7 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -147,6 +147,17 @@ dedent_re = re.compile(r'^\s+raise|^\s+return|^\s+pass') # Utilities #----------------------------------------------------------------------------- +def is_integer_string(s:str): + """ + Variant of "str.isnumeric()" that allow negative values and other ints. + """ + try: + int(s) + return True + except ValueError: + return False + raise ValueError('Unexpected error') + @undoc def softspace(file, newvalue): """Copied from code.py, to remove the dependency""" @@ -1548,7 +1559,7 @@ class InteractiveShell(SingletonConfigurable): break parts.append(var) for ind in indices: - if ind[-1] != "]" and not ind[:-1].isnumeric(): + if ind[-1] != "]" and not is_integer_string(ind[:-1]): parts_ok = False break parts.append(ind[:-1]) @@ -1602,7 +1613,7 @@ class InteractiveShell(SingletonConfigurable): if idx == len(oname_rest) - 1: obj = self._getattr_property(obj, part) else: - if part.isnumeric(): + if is_integer_string(part): obj = obj[int(part)] else: obj = getattr(obj, part) @@ -1669,7 +1680,7 @@ class InteractiveShell(SingletonConfigurable): # # The universal alternative is to traverse the mro manually # searching for attrname in class dicts. - if attrname.isnumeric(): + if is_integer_string(attrname): return obj[int(attrname)] else: attr = getattr(type(obj), attrname) diff --git a/IPython/core/tests/test_oinspect.py b/IPython/core/tests/test_oinspect.py index f231280..0c7c0da 100644 --- a/IPython/core/tests/test_oinspect.py +++ b/IPython/core/tests/test_oinspect.py @@ -395,6 +395,19 @@ def test_qmark_getindex(): ip.run_cell("container[0]?") assert "container" not in ip.user_ns.keys() +def test_qmark_getindex_negatif(): + def dummy(): + """ + MARKER 3 + """ + + container = [dummy] + with cleanup_user_ns(container=container): + with AssertPrints("MARKER 3"): + ip.run_cell("container[-1]?") + assert "container" not in ip.user_ns.keys() + + def test_pinfo_nonascii(): # See gh-1177