top | item 8386361

Python REPL with syntax highlighting, autocomplete and multiline editing

173 points| powerbook5300CS | 11 years ago |github.com | reply

36 comments

order
[+] aidos|11 years ago|reply
This is actually brilliant. It fixes my (relatively minor) gripes with the standard iPython front-end. Namely the multiline mode is miles better, so so much better.

Already mentioned on the thread somewhere else is an issue with autocompletion on imported modules, but that sounds like a bug that will be fixed.

I'm using the ipython mode and there are a couple of differences. For example I'm used to typing 'hist -l 100' to see the recent history, now I need to use the magic ipython variant '%hist -l 100'. Not a big deal, just slightly different behaviour.

The vi-mode is actually not too bad. For me it's good enough to be used in this context. Would be great if it was more complete (eg, daw doesn't work). Maybe it could make use of neovim at some point?

I LOVE that a syntax error means the line isn't flushed so you can fix the issue and hit enter to execute it again. That's a really smart enhancement that I hadn't even noticed was a total waste of time in my workflow until now.

Does it read my local iPython config profile? I use auto-reloading heavily for hot code swapping during my development, will that still work?

Edit: just tested and the iPython auto-reloading isn't working. Maybe it needs to be converted to run as a front-end to get the full power of iPython?

Also, needed to do PYTHONPATH=. ptipython --vi to be able to load modules from the directory in which I started the app.

[+] jonathan_s|11 years ago|reply
Thanks for the feedback.

About "daw": it looks like I forgot about that. To be fixed, but right now use "diw" instead. (Please create a github issue if there are some other important key bindings missing.)

At the moment, I don't know yet about auto-reloading in IPython, but that's worth looking at.

About the PYTHONPATH, that's easy to fix. (Should we always add the current directory to the path in a REPL?)

[+] crucialfelix|11 years ago|reply
> For example I'm used to typing 'hist -l 100' to see the recent history, now I need to use the magic ipython variant '%hist -l 100'.

I'll take that any day over list (the type) vs list (the ipython command) confusion and not being able to use various single letter variables

[+] devnonymous|11 years ago|reply
Disclaimer: this comment includes a shameless plug to something I wrote. Read further only if you are not offended by this behavior. I am just trying to help others reading this post who like me think IPython might be a bit of an overkill at times but aren't really happy with the default python prompt. Now my comment ...

This Looks really nice and it does seem like it adds a lot to IPython. That said, I personally prefer working in a proper editor (rather than an approximation) when doing multi-line editing of commands on the prompt. So I wrote a small function to just invoke the editor with the lines in the current prompt 'buffer'[1]. This gives all the things like autocomplete and syntax-highlighting for free (albeit, when you are in the editor). Further more you may open up other buffers to refer to other code while editing the thing that you are on your prompt.

To see what I mean -- https://gist.github.com/lonetwin/5902720

Furthermore, what I wrote is a small enough file to copy as a .pythonrc (rather than pip install ...).

[1] ...and then I added more ...a lot more.

[+] nobodysbusiness|11 years ago|reply
If you're looking for a better python prompt, you might want to check out BPython as well: http://bpython-interpreter.org/
[+] vishvananda|11 years ago|reply
I'm a big fan of bpython (especially bpython-curtsies), but I have to admit the multiline editing and the navigation keybindings in this are very nice. Bpython lets you rewrite the last line via ctrl-r but it doesn't let you navigate through a multiline function. I find the way bpython shows the docstring when you type the open paren for a method extremely useful, however, so that would be a nice addition here.
[+] gknoy|11 years ago|reply
I used to use BPython. I really liked its way of presenting autocomplete. However, its scrolling drove me NUTS (it doesn't use your terminal's scroll). I was much happier when I switched to IPython.

Both are leagues better than the plain REPL, though. :)

[+] orkoden|11 years ago|reply
For ruby there's something similar called pry http://pryrepl.org which I've been using instead of irb for a while now. It's great news to do something similar with python now too.
[+] rattray|11 years ago|reply
This is awesome. Can't imagine wanting to use anything else now.

Folks who like the library aspect of this and are interested in building similar things for bash instead of python might want to check out twosheds [0], a library by a friend of mine that lets you do zsh-type-stuff in Python.

[0] https://github.com/Ceasar/twosheds

[+] PythonicAlpha|11 years ago|reply
Very useful, indeed.

One thing that I am missing already is searching inside the history for a specific input. There is some search facility (in vi mode, you can press / and it says that it will search), but I don't know how it works, since it gives no results.

Ok, now I see, it just marks the search results, but does not give an immediate result. That is not, what I would expect and what would be useful for me. In ksh, I believe, there was the possibility to search backwards in history and when it was performed, the most recent input line was put into the active input for replay or editing.

[+] jonathan_s|11 years ago|reply
This could be confusing. '?' is for searching backwards, '/' for searching forward. Because we are in a multiline environment, I preferred the Vi keybindings instead of the readline bindings (where '/' goes backwards.)

Also the ControlX-ControlL sequence can complete a line based on the history. (Type "imp"C-X C-L and you get your last import.)

[+] giancarlostoro|11 years ago|reply
It's refreshing to see that it works with Python 3 as well. Thanks.
[+] arocks|11 years ago|reply
Looks like an IPython replacement with syntax highlighting as you type. Couldn't this be something that could be added to IPython itself?
[+] jonathan_s|11 years ago|reply
(author here.)

The idea is indeed that ``ptpython`` could become the terminal front-end for IPython.

The only thing on which ``prompt_toolkit`` is focussing, is reading input from stdin and returning it to the application. IPython is a very powerful execution environment, but the current command line interface which uses GNU readline lacks decent multiline editing and syntax highlighting.

There is a proof of concept of what the integration could look like: https://github.com/jonathanslenders/python-prompt-toolkit/bl... But in the end it would be nice to have this as a part of IPython itself.

[+] tzudot|11 years ago|reply
> Run ptipython (prompt_toolkit - IPython), to get a nice interactive shell with all the power that IPython has to offer, like magic functions and shell integration.

In fact, you can run it with IPython too.

[+] 1331|11 years ago|reply
Great job!

I really like the multi-line editing and IPython-style prompts. The syntax highlighting feature is nice as well, and it can be turned off with a flag. I am not a fan of auto-completion, however, so I wish there were a flag to turn it off as well (perhaps --autocompletion=off).

[+] jonathan_s|11 years ago|reply
Thank you for the feedback. I'll add an option to turn off the automatic autocompletion.
[+] arenaninja|11 years ago|reply
This is amazing. My niece has recently been interested in "doing what I do", and Python is the language of choice for that. I was thinking of using bpython, but I guess I'll have my choice of REPLs
[+] jeffrand|11 years ago|reply
This is great, I really enjoy this. The one thing I'd be interesting in contributing is using ipython's sqlite history database if a user chooses to.
[+] firemanphil|11 years ago|reply
This is fantastic and completely intuitive. After wasting many hours fiddling around with Vim plugins so that I can use autocompletion, this is a relief.
[+] Beltiras|11 years ago|reply
Maybe I am just doing something wrong, but ptipython does not autocomplete anything I import.
[+] jonathan_s|11 years ago|reply
(author here)

I noticed. You're not doing it wrong. It's a bug and it will be fixed asap.

[+] stuaxo|11 years ago|reply
Very very nice. Does it work in windows too ?
[+] jonathan_s|11 years ago|reply
I'm sorry about this, at the moment there is no Windows support.

However the architecture of the library decouples the input and output from the rest, so it should be possible to plug in something to make it compatible with the Windows terminal.

For me personally, it doesn't have priority, but maybe in the future I will have a look.

[+] mrmch|11 years ago|reply
This is freaking awesome. Vi-mode is huge.
[+] sgt|11 years ago|reply
Getting some errors trying to define simple functions and call them:

  In [3]: foo(Exception in thread Thread-159:
  Traceback (most recent call last):
  File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/threading.py", line 810, in __bootstrap_inner
    self.run()
  File "/Library/Python/2.7/site-packages/prompt_toolkit/__init__.py", line 200, in run
    callback()
  File "/Library/Python/2.7/site-packages/prompt_toolkit/__init__.py", line 440, in run.7.6
    completions = list(line.completer.get_completions(document))
  File "/Library/Python/2.7/site-packages/prompt_toolkit/contrib/python_input.py", line 449, in get_completions
    for c in script.completions():
  File "/Library/Python/2.7/site-packages/jedi/api/__init__.py", line 161, in completions
    for call_sig in self.call_signatures():
  File "/Library/Python/2.7/site-packages/jedi/api/__init__.py", line 574, in call_signatures
    self._pos, user_stmt)
  File "/Library/Python/2.7/site-packages/jedi/cache.py", line 90, in wrapper
    value = optional_callable()
  File "/Library/Python/2.7/site-packages/jedi/api/__init__.py", line 572, in <lambda>
    _callable = lambda: self._evaluator.eval_call(stmt_el)
  File "/Library/Python/2.7/site-packages/jedi/evaluate/__init__.py", line 226, in eval_call
    return self.eval_call_path(path, par, s.start_pos)
  File "/Library/Python/2.7/site-packages/jedi/evaluate/__init__.py", line 240, in eval_call_path
    search_global=True)
  File "/Library/Python/2.7/site-packages/jedi/evaluate/__init__.py", line 113, in find_types
    return f.find(scopes, resolve_decorator, search_global)
  File "/Library/Python/2.7/site-packages/jedi/debug.py", line 51, in wrapper
    result = func(*args, **kwargs)
  File "/Library/Python/2.7/site-packages/jedi/evaluate/finder.py", line 46, in find
    names = self.filter_name(scopes)
  File "/Library/Python/2.7/site-packages/jedi/evaluate/finder.py", line 89, in filter_name
    scope = name.parent.parent
  File "/Library/Python/2.7/site-packages/jedi/cache.py", line 139, in wrapper
    result = func(self)
  File "/Library/Python/2.7/site-packages/jedi/api/interpreter.py", line 69, in parent
    module = __import__(module_name)
TypeError: __import__() argument 1 must be string, not None
[+] lake99|11 years ago|reply
HN is not the right place for reporting bugs of this sort. Report it on github.