Why Jedi not Rope
written on Saturday, January 19, 2013
Recently I was asked to compare Jedi with Rope, because saying "it's better" was just not good enough. :-)
Now, in the python world there are 3 fairly good auto-completion systems:
The only other autocompletion library is PySmell, which is just very simple. Doesn't understand code that is a little bit more complicated. Other solutions include PyDev, PyDiction, and pythoncomplete, which are all fine but don't offer a good autocompletion system.
I will compare Rope and Jedi now. I'm not comparing with PyCharm now, it's not as good as Jedi, but I'll talk about that another day.
So the main difference between Rope and Jedi is their goal. You can see that in the description:
- Rope, a python refactoring library.
- Jedi, an awesome autocompletion library for Python.
Rope was never really intended to be an autocompletion library and therefore has a natural disadvantage in this field.
So I went down to the real business: Checking for cases that might work in one library, but not in the other. So I sat down and used Spyder to compare a few things (Spyder is using Rope, but is considering to switch to Jedi). As expected I haven't found anything that is working in Rope, but not in Jedi. With Rope the following things don't complete (work in Jedi though):
- __call__ and other magic methods
- completion within classes/functions
- dynamic arrays
- *args, **kwargs
- simple sys.path manipulations
- invalid code, Rope cannot handle too many errors, in Jedi it will always work if some parts of the code are valid.
- performance in big files
Rope isn't "bad". It's just not as good as Jedi for autocompletion. But it's pretty clear that Rope fails to understand some basic principles of Python. For example list.append in one place will already make Rope useless.
Jedi has a very nice and user-friendly API:
>>> import jedi >>> source = '''import json; json.l''' >>> script = jedi.Script(source, 1, 19, 'example.py') >>> script <Script: 'example.py'> >>> completions = script.complete() >>> completions [<Completion: load>, <Completion: loads>] >>> completions.complete 'oad' >>> completions.word 'load'
So, what about Rope? The documentation says something like this:
from rope.base.project import Project project = Project('.ropeproject') from rope.contrib import codeassist # Get the proposals; you might want to pass a Resource proposals = codeassist.code_assist(project, source_code, offset) proposals = codeassist.sorted_proposals(proposals) proposal.name
While I don't know it it's possible to do the same with Rope and Jedi, it's certainly clear that there's no documentation around for Rope. It's also not clear how Rope would check for relative imports, because Rope simply doesn't know where the file it is completing is situated at (the project folder might be in an other directory).
This is really the place where Rope shines. I don't want to talk about this too long, but Jedi has only very limited refactoring possibilities like renaming. There's a discussion going on on github, how to improve the refactoring in Jedi. But Rope will probably always be better there.
Like Jedi is not really suited for refactoring, Rope is not really suited for autocompletion. In a fully fledged IDE I would recommend to use Jedi for autocompletion and Rope for refactorings. I think these two complement one another very well.
But if you are asking yourself: Which one should I choose for my editor (vim, emacs, sublime, etc)? The answer should always be Jedi. You can always add refactoring later on. But what you want in the beginning is a good and rock-solid autocompletion library.