-
-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Add options to tkinter widgets #4363
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
Add options to tkinter widgets #4363
Conversation
@Hawk777 What do you think about the difference between |
Rebasing on top of latest master because there's not yet any conversations that could be lost by doing that |
7c1d1f4
to
cbeab82
Compare
I’m uncertain how I feel about the Second, I worry about discoverability; where would all these Typeshed-specific rules be documented? You have this stronger type checking, but how will people ever know that it exists? Certainly not from reading the Python documentation for tkinter, which explicitly states that Neither of these is necessarily a reason to reject, but I think they need to be thought through. |
Tkinter stubs have other things that need documentation too:
I think having to look up these things from typeshed pull request and issues history would be pretty bad. Has there been similar "type hints of this library need documentation" problems with other libraries in the past? If so, has the documentation went to |
Looking at tkinter documentation on docs.python.org, there's already a big list of references that people should look at, and maybe another item in the list for using type hints with tkinter would be a good idea. Who should maintain that though? I don't think that |
Maybe I'll mention another idea: put a markdown file into this typeshed repo and link to that from python docs. Maybe that would be a little weird, but it would be very easy to keep it updated as pull requests get merged to typeshed. |
Previously I allowed them to be numbers too, which could be useful for letting the user e.g. choose a port number from a list of acceptable ports numbers. I think that doesn't come up as often as would often as accidentally passing numbers for values. More importantly, this makes the type more readable in e.g. IDE autocompletion or mypy errors.
…cript-pr-squashed
Even though this pull request requires some conversation before getting merged, I'd like to make progress with this. The tkinter stubs won't be usable to me before this (or some similar pull request) gets merged. @srittau @hauntsaninja It's been quiet for a while, and CONTRIBUTING.md seems to say that it's ok to ping after "more than a few days". |
This reverts commit fc73134.
…cript-pr-squashed
I created #4453 to fix |
…cript-pr-squashed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks again for your hard work and patience! You've been exceptionally thorough; the test script and the real world testing both give a lot of confidence. I did some more spot checking and things look good. If there are more improvements to be made, let's make them on master :-)
Tkinter options now have type hints that describe which values are valid when setting the options. For example,
tkinter.Label(relief='sunkenn')
now creates a mypy error. The correct types for the options come from Tk's manual pages as described in__init__.pyi
. This affects__init__
,config
,configure
,cget
,__setitem__
and__getitem__
methods because those are the methods that deal with widget options.Looking up the value of an option always returns
Any
, because tkinter doesn't make much effort to ensure that the return values have consistent type. In practice, they can be pretty much anything in funny corner cases, and figuring out which of the possible types actually come up frequently enough for type hints would be a lot of work.In tkinter,
widget['foo'] = bar
andwidget.config(foo=bar)
do the same thing, but they type-check differently: thewidget['foo'] = bar
syntax allows'foo'
to be any string (e.g. a variable, not necessarily aLiteral
) andbar
to be any object, whilewidget.config(foo=bar)
checks the existence of the option and the type ofbar
. Similarly,cget
takes aLiteral
argument but__getitem__
takes a string. This is done because:foo = 'sunken'
isstr
rather thanLiteral['sunken']
, so fixing code that doeswidget.config(relief=foo)
can be done without a# type: ignore
comment by changing it towidget['relief'] = foo
.bar = 'relief'
and doingwidget[bar] = 'sunken'
works.This also includes a script that checks whether the types of widget options actually work at runtime (stubtest doesn't work well with the generous**kwargs
usage in tkinter) and the travis configuration to make that part of the CI build. Usually it takes about 22 seconds to run, which is a lot quicker than any of the other CI things. The script creates tkinter widgets, parses a small subset of type hint syntax withast
, creates possible values of the options based on those type hints and tries to set the options of the widgets.Some classes intkinter/ttk.py
inherit from other classes and break the Liskov substitution principle by not having all the widget options of the base class. In those cases, I made the stubs not inherit and instead usedmethod = BaseClass.method
.I added a--verbose
option totests/pytype_test.py
for finding pytype issues more easily, but that's disabled in the travis config.This pull request contains a lot less copy/pasta than I initially thought it would contain, but there's still a lot of it. The copy/pasta is quite readable even though I used a script to initially generate it. The script is not included in this pull request because I think the copy/pasta is maintainable as is, and learning to use my script to maintain it would be more work than with copy/pasta. I added comments about the trickiest options to the stubs.