-
-
Notifications
You must be signed in to change notification settings - Fork 4.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
function specific tab completion via annotations #2701
Conversation
That's nice ! Not much time to look at it, but the travis faillure are mostly issues with |
@Carreau, unfortunately, there doesn't seem to be a way to skip the doctests that run on the module docstring, since you can't decorate the module docstring. |
Oh, it was on the module docstring, I didn't saw that, I only saw doctest errors :-) |
Wow, fantastic! I'll give this a whirl in a few days. |
You could try setting |
It's unfortunate that the easiest way to add return completions in Python 2 is @tab_complete(a=str, **{'return': str})
def f(a):
return a + '1' is the same as @tab_complete_return(str)
@tab_complete(a=str)
def f(a):
return a + '1' ? |
@takluyver, good idea. Setting @asmeurer, I added the python2 convenience decorator. |
In the qtconsole, the tooltip and the tab completions come up on top of each other for entries like |
A few unordered thoughts:
|
I wouldn't filter out class methods - they can still actually be called on the instance, so it's valid for them to show up in tab completions. The question about tuples nrings us back to the discussion on python-ideas - should that syntax be for "2-tuple of str, int", or for "either str or int"? In any case, I suspect the complexity of tracking those variables isn't worth it. |
Maybe you're right. I feel like the most common thing is 2-tuple of str, int. But perhaps it's not worth it. A new issue with architectural implications is that most of this code fails with functions defined in C (or cython) since they can't be properly introspected. You also can't set random attributes on functions defined in C trying to set I was trying to manually "decorate" numpy by parsing the docstrings, but since so many of the functions are defined in C, the possibilities are really limited. |
Also, it would be possible to have both semantics with something like
given them the two different semantics But I am -1 on this idea. |
Or would it be the much less satisfying:
|
right. that doesn't provide much functionality with the current code (just |
I think that unpacking return values quickly gets complex. E.g. if the return value is guaranteed to be a 2-tuple, I would often unpack it: But before long, you're almost reimplementing Python to keep track of variable changes. And if that's the route we want to go down, we should look more closely at existing refactoring and completion solutions (like rope and jedi). And in any case, let's not try to do too much in one pull request. |
Yeah. I concur. I think we're on the same page. |
@takluyver, do you think it's better to store the function tab completion info on the function (e.g. The first seems less spooky, but doesn't let you do builtins like |
I think it seems pretty reasonable to only support a single return object (and therefore use |
Hmm, it's annoying that you can't attach arbitrary information to a compiled function. I wonder if it's worth looking for information both on the function, and then in a global registry? E.g. our display machinery looks for methods like Alternatively, perhaps we should look at a module-level structure - then packages like numpy could add a dictionary of annotation-like info to the module, rather than having to play the 'are we inside IPython' game to add the information to an IPython registry. |
What's the decision here on whether this extension belongs in IPython vs separately maintainted? It seems like bundling every new extension in IPython misses much of the point of extensions. Pinging @ellisonbg and @fperez on that one. |
At a glance, I don't think that module is really an extension (as in something that you would do I also think we might have to rationalise our tab-completion infrastructure a bit to better cope with more complex parsing. |
I would argue for this one to be included.
But it's your decision. I could also see very nice tab completion being an external library that plugs in to IPython. |
I think there are 2 things here.
So I think the question of having this part with the decorator "separate" make sens, because it can be used without the rest of this PR or IPython. |
BTW, it conflicts now. |
I agree with @minrk that most "extension" like things should not be in IPython itself. My preferences would be:
I am -1 on the in between of having it as an extension that is shipped with IPython. |
Sure. I realize that this PR is called an "extension" (and there's code in the 'extension' directory), but most of it is additions to the completer module that enable the tab completion mechanism to be extended via annotations. That's the core feature. The question, to me, is, do you want that in IPython? |
I like the functionality, but this is a lot of added code and complexity to an already messy and complex part of our code base. It adds a lot of potential for future breakage points and we will have to maintain it. All of that points to not including it in IPython. I don't know enough about our completer logic to know if/how this could be simplified. I would like to get a good read on these issues from the other core devs. |
On the one hand, it is quite a bit of extra, non-trivial code for something that users aren't especially crying out for. On the other hand, tab completion is often one of those things that you don't know how valuable it is until you're using it heavily. And this wouldn't be much use as an extension - it's only likely to see much use if it's a default component of IPython. This is made harder by the fact that the completer stuff is some of the older, thornier code, that I don't think any of us are especially familiar with. I think I'd regretfully defer this for now, but hope that parts of it can be reintroduced when someone gets to spring-cleaning the completer stuff. |
Is that spring cleaning on anyone's todo list? I agree that the existing completer code is quite obtuse. I had to learn its ins-and-outs to write this PR. I have some ideas about how it could be improved, that I can share with whoever. |
Robert, We are discussing this over here: www.hipchat.com/ghtNzvmfC On Wed, Feb 20, 2013 at 4:28 PM, Robert McGibbon
Brian E. Granger |
It's on my 'maybe get to this one day' list. ;-) You might be the world expert on it after doing this pull request, so if you want to have a go at it, be our guest. Off the top of my head, I think the things to look at include:
No doubt there'll be plenty of other fun things waiting to be discovered ;-) |
After reading the whole code, here's my take on the matter: this is simply too complex to put into IPython right now, and part of the complexity stems from the fact that it's hacking around a sub-optimal completion API that doesn't return the right pieces of information in various places. There are also a number of minor issues with the code itself, but since I don't think it can go in at all, I don't want to get into line-by-line review. The functionality is potentially quite useful if adopted widely, but because people are very reluctant to put ipython dependencies into their own codes, I'm somewhat skeptical of how well that will go. Obviously we want to break the chicken-and-egg problem, but right now the cost/benefit analysis just isn't there. Furthermore, the 2.x version of this is hideous (no fault of yours, @rmcgibbo, its' just how the language goes). I don't think many people will adopt it for 2.x, but I can see it working much better in 3.x. For all these reasons, here's the path forward I see:
Note that the two parts above should be separate: people should be able to annotate their codes without creating any dependency on IPython. The annotations are just metadata, possibly aided by your tool. And only users of IPython would load the extension and thus take advantage of the metadata. In doing so, I'd try to see if it's possible for the py3 version to require zero imports and rely strictly on the annotation protocol (maybe that's already the case, I didn't study all your examples in detail). That way we'd have a protocol for this, rather than a dependency. @rmcgibbo, you've done a terrific job and we really appreciate it. So I hope you can continue working with us, we just need to find the right path forward. |
For reference, the h5py custom completers do exist and rely on our API. So let's make every reasonable effort to come up with a solution that doesn't break their code, even if it means making a slightly uglier API (such as having the new one use different names and keep deprecated methods with the old functionality). |
Also @rmcgibbo, have a look at that h5py completer to see if a similar regex-based hook isn't sufficient to trigger your completer machinery without further changes. |
@rmcgibbo I think the first step will be to remove everything from this PR that is not related to your refactoring of the core completer logic. I am hopeful that we can come up with a good API that doesn't require completely rewriting the inner workings of everything. I would try to think about what the simplest API is that will work for you. I am hopeful that a small amount of refactoring will suffice. I don't want you to feel like you have to completely rewrite the completer logic to implement your stuff. As Fernando said, we really appreciate your work - please don't hesitate to bug us with questions... |
If we're talking about refactoring the core completer logic, I suggest we On 21 February 2013 05:43, Brian E. Granger notifications@github.comwrote:
|
@takluyver agreed. |
@rmcgibbo, just read your summary of the issues, this is fantastic work. Thanks so much, we'll continue the discussion off that. I'm very impressed. |
@fperez, where is the best forum in which to continue the discussion? Once I've finished that document (I want to add more on the proposal), do you want me to ping this thread, or is another format preferable, such as using that text as the basis of a new "Proposal" GH issue? |
Got it. |
Yup, go ahead and start an IPEP, it's the perfect way to move forward these kinds of more complex discussions. I just noticed typeahead.js from Twitter, I'd suggest thinking about what could be done with this kind of tool on the client side if we had a richer completion API. We can always flatten the returned object into a simple list for readline, but our internal design shouldn't be constrained by that at all. |
Thanks @fperez. That's awesome. So many good ideas. |
@rmcgibbo, I'm going to be at Stanford giving a talk about IPython on Friday at 10am, in the Stats dept. How about we book some time later that day to pound on this IPEP? |
@fperez, yeah, sounds good. I have a meeting with my advisor from 2-3pm, but otherwise I'm free. Your schedule is probably more constrained than mine. Where is the talk? If it's a public seminar, I think some lab members and I might like to come. |
SPECIAL TALK |
Awesome. I'll come up & find you after the talk and we can figure something out? |
yes! |
This is a new attempt at #2636. The feature enables custom tab completion for different arguments of a function, and also for the return value of a function (without calling it).
It's easier to show in action though. Check it out!
Here's tab completion on the return value of a function, without ever
eval
ing the functionNote that sense this never calls the function, all the tab completion is based on methods defined on the
str
class. If you notate the return value as some class that dynamically defines its methods when it isinstantiated, the tab complete engine is not going to be able to find them. There's no way around this without actually invoking the code on the TAB keypress, which is not desired (and is already possible by configuring your ipython config file).
Here, tab completion on the first argument only shows literal strings and directories that match a
glob
pattern. For the second argument, it shows some string literals.The default type of tab completion is based on
isinstance
matching. You could also be explicit about it:All of this functionality is possible in python2 syntax (without PEP3107 annotations) by calling the
@tab_complete
decorator with keyword arguments.The design here was influenced by Nick Coghlan's emails on python-ideas, and an annotation-based typechecking library on activestate.