Add trait-names autocompletion support - #515
Conversation
maartenbreddels
left a comment
There was a problem hiding this comment.
I think this is a 'dream coming true' for me. This increases usability so much!
Great work.
|
@martinRenou since |
|
I also wonder whether you might be able to leverage |
|
The thing is I don't really know where to put this code if it's not in a decorator. Right now, because it's in a decorator, it gets executed when the class is created. |
|
I used this snippet: def create_parameter(cls, name):
trait = getattr(cls, name)
if trait.default_value == traitlets.Undefined:
default = Parameter.empty
else:
default = trait.default_value
return Parameter(name=name, kind=Parameter.KEYWORD_ONLY, default=default) |
|
@martinRenou I think if you were to drop this code right here that you'd achieve the same effect - each time a new |
|
So, I came up with this code (I will take your comment into account @maartenbreddels): class MetaHasTraits(MetaHasDescriptors):
"""A metaclass for HasTraits."""
def setup_class(cls, classdict):
cls._trait_default_generators = {}
traits = [
(name, value.default_value)
for name, value in cls.class_traits().items()
if not name.startswith('_')
]
cls.__init__.__signature__ = Signature([
Parameter(name, kind=Parameter.KEYWORD_ONLY, default=default)
for name, default in traits
])
super(MetaHasTraits, cls).setup_class(classdict)But it is REALLY broken. class Identity(HasTraits):
username = Unicode()Then in the Note that the problem still stands with the decorator implementation. |
|
Note to self: The following cannot be supported too: class Identity(HasTraits):
username = Unicode()
address = Unicode()
def __init__(self, name): # The __init__ function does not take **kwargs
super(Identity, self).__init__()
self.username = nameThe fact that the EDIT: Assigning to the |
|
In order to support this use case: class Identity(HasTraits):
username = Unicode()I create an |
|
@martinRenou I don't think you should modify the Also, when you do modify the signature, you should be sure to preserve the original as well by inserting your KEYWORD_ONLY parameters here within the signature. def __init__(self, a, b, c, *args, , **kwargs):
^This will require you to read the original signature, find the index of a parameter whose index = None
parameters = list(sig.parameters.values())
for i, param in enumerate(parameters):
if param.kind is Parameter.VAR_KEYWORD:
index = i
if index is not None:
parameters[index:index] = list_of_dynamic_trait_parameters |
|
Yeah I also thought about it for later improvements.
I'm only assigning a new `__init__` method if there is no. I'm not sure
what are the options in this case?
|
|
I can’t think of a real scenario where |
Well, this use case: class Identity(HasTraits):
username = Unicode()In this case
I totally agree, this is bad. Please don't merge it I don't want to be responsible for that 😄 |
|
@martinRenou of course! I see now - you'd be replacing the signature on the parent class... I don't think there's a way around replacing the Given this, I think your decorator idea is better. As nice as it would be to have auto completion by default I think defining
You decorator solves these problems by:
|
|
I think having an opt in method using decorators would be the safest
option. Thanks for helping out Ryan!
(from mobile phone)
…On Sat, 30 Mar 2019, 07:04 Ryan Morshead, ***@***.***> wrote:
@martinRenou <https://github.com/martinRenou> of course! I see now -
you'd be replacing the signature on the parent class.
I think your decorator idea is better.
As nice as it would be to have auto completion by default I think defining
__init__ on all HasTraits subclasses might be a problem:
1.
Its quite "magical" - there's a real (though unlikely) possibility
this causes a downstream bug somewhere.
2.
There might be negative performance impacts since every instantiation
would cause you to trace the __init__ method of every class in the MRO.
You decorator solves these problems by:
1.
Making the magic just a *little* more explicit.
2.
Allowing you to remove the decorator if you're experiencing
performance issues.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#515 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABryPY5igu90MvVvafE8LcSA0agexccRks5vbv5ggaJpZM4cSFE8>
.
|
|
Or we could keep the implementation simple and unmagical in the This way we could document that if one wants autocompletion in their traits class they simply need to implement |
|
@martinRenou I think that could be reasonable, however IMO the decorator looks nicer. from traitlets import HasTraits, has_autocompletion
@has_autocompletion
class MyClass(HasTraits):
....VS from traitlets import HasTraits
class MyClass(HasTraits):
def __init__(self, **kwargs):
super().__init__(**kwargs) |
|
I agree it looks nicer. So if we go for the decorator, we need to make it really clear in the documentation that it creates an One thing that annoys me is that this does not work with |
|
@martinRenou yes be sure to add documentation and tests (Traitlets needs more of both). Link to relevant Jedi issue: davidhalter/jedi#1058 You should open up an issue against IPython too if you don't think it will be fixed in Jedi. |
|
@maartenbreddels @rmorshea The issue was fixed in Jedi and must be included in the last release (0.15)! 🎉 I'll give this PR another shot and resolve your comments @rmorshea. And actually IPython depends on |
|
So the is issue is indeed fixed. But we need to overwrite the Discussing with Maarten on gitter. We agree that the decorator solution is not only nicer, it's also less magical, and it won't mislead the user if the developer implements a custom |
1d1de85 to
25d5b4b
Compare
|
What's remaining in this PR:
|
25a084b to
8b9ab4d
Compare
|
Thanks for your comments @rmorshea, I will rename the decorator.
Shouldn't I open my PR against |
|
If I recall we haven't done a release off master in 3 years, but looking at it now I think minrk synced 4.x with 4.3.x recently |
|
I think you could do it 4.3 though since this isn't a big feature add. |
|
Replaced by #538 |
|
I think we should still have a PR against |
|
Ok I will restore this PR then |
|
I need to cherry-pick the commits from #538 |
ec98b62 to
f4c6f4f
Compare
|
Done :) |
|
I think this will boost traitlets/widgets usability 1000 fold, many thanks @martinRenou for pushing on this, and thanks @rmorshea for reviewing this, this made my day :) |
cc @maartenbreddels @SylvainCorlay
Add a trait-names autocompletion support for

HasTraitsclassesUnfortunately, it does not work with
jedi. Which means that this works foripython=7.1.1by default, and it will work with otheripythonversions only ifjediis not installed.I failed to find a way to make it work with
jedi.