Search code examples
ipythontokenizemultiline

Issue with multiline TokenInputTransformer in IPython extension


I am trying to use a TokenInputTransformer within an IPython extension module, but it seems that there is something wrong with the standard implementation of token transformers with multiline input. Consider the following minimal extension:

from IPython.core.inputtransformer import TokenInputTransformer

@TokenInputTransformer.wrap
def test_transformer(tokens):
    return tokens

def load_ipython_extension(ip):
    for s in (ip.input_splitter, ip.input_transformer_manager): 
        s.python_line_transforms.extend([test_transformer()])
    print "Test activated"

When I load the extension in IPython 1.1.0 I get a non-handled exception with multiline input:

In [1]: %load_ext test
Test activated

In [2]: abs(
   ...: 2
   ...: )
Traceback (most recent call last):
  File "/Applications/anaconda/bin/ipython", line 6, in <module>
    sys.exit(start_ipython())
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/__init__.py", line 118, in start_ipython
    return launch_new_instance(argv=argv, **kwargs)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/config/application.py", line 545, in launch_instance
    app.start()
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/terminal/ipapp.py", line 362, in start
    self.shell.mainloop()
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 436, in mainloop
    self.interact(display_banner=display_banner)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/terminal/interactiveshell.py", line 548, in interact
    self.input_splitter.push(line)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/core/inputsplitter.py", line 620, in push
    out = self.push_line(line)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/core/inputsplitter.py", line 655, in push_line
    line = transformer.push(line)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/core/inputtransformer.py", line 152, in push
    return self.output(tokens)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/core/inputtransformer.py", line 157, in output
    return untokenize(self.func(tokens)).rstrip('\n')
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/utils/_tokenize_py2.py", line 276, in untokenize
    return ut.untokenize(iterable)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/utils/_tokenize_py2.py", line 214, in untokenize
    self.add_whitespace(start)
  File "/Applications/anaconda/lib/python2.7/site-packages/IPython/utils/_tokenize_py2.py", line 199, in add_whitespace
    assert row >= self.prev_row
AssertionError

If you suspect this is an IPython bug, please report it at:
    https://github.com/ipython/ipython/issues
or send an email to the mailing list at [email protected]

You can print a more detailed traceback right now with "%tb", or use "%debug"
to interactively debug it.

Extra-detailed tracebacks for bug-reporting purposes can be enabled via:
    %config Application.verbose_crash=True

Am I doing something wrong or is it really an IPython bug?


Solution

  • Kinda late answer but, I was trying to use it in my own extension and just had the same problem. I've solved it by simply removing NL from the list (it's not the same as NEWLINE token which end statement), NL token only appears inside [], (), {} so it should be safely removable.

    from tokenize import NL
    @TokenInputTransformer.wrap
    def mat_transformer(tokens):
        tokens = list(filter(lambda t: t.type != NL, tokens)) 
        return tokens
    

    If you are looking for full example, I've posted my goofy code there: https://github.com/Quinzel/pymat