-
-
Notifications
You must be signed in to change notification settings - Fork 153
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
PR: Support mypy #217
PR: Support mypy #217
Changes from 9 commits
0a72a91
52c6039
80dda11
bbf4247
59c8ab7
203d4f4
d38fcab
91e5834
7754e75
4a3aeb4
135b74c
b279790
b05c7c7
3d171a5
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -71,6 +71,24 @@ conda install qtpy | |||||
``` | ||||||
|
||||||
|
||||||
### mypy | ||||||
|
||||||
A CLI is offered to help with usage of QtPy including the subcommand | ||||||
`qtpy mypy args` which generates command line arguments similar to the | ||||||
following which help guide mypy through which library QtPy would have used | ||||||
so that mypy can get the proper underlying type hints. | ||||||
|
||||||
``` | ||||||
--always-false=PYQT4 --always-false=PYQT5 --always-false=PYSIDE --always-true=PYSIDE2 | ||||||
``` | ||||||
|
||||||
Use such as: | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Fix grammar. Also, if something in the below is intended to be replaced, such as the path to the environment/QtPy, please say so, e.g. by adding something like the following: ", replacing <env/bin/qtpy> with the path to the QtPy installation:" Thanks! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand how that will help. If people know "the path to their qtpy installation" then they will know to change this. Also, do we need to cover There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I guess my intention was that its better to be explicit rather than implicit about what users are expected to replace, if the example is intended to be of practical value. However, given your point, perhaps its simpler to just specify the default invocations of the |
||||||
|
||||||
```bash | ||||||
env/bin/mypy --package mypackage $(env/bin/qtpy mypy args) | ||||||
``` | ||||||
|
||||||
|
||||||
## Contributing | ||||||
|
||||||
Everyone is welcome to contribute! | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,3 @@ | ||||||||||||||||||
import qtpy.cli | ||||||||||||||||||
|
||||||||||||||||||
qtpy.cli.cli() | ||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
A little extra boilerplate, but this allows pointing the setuptools entrypoint here (see below) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see the major upside as compared with encouraging the hazardous behavior of making files both directly runnable and importable. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm afraid I don't follow the reasoning here. Could you explain why this behavior is more hazardous in this context of a trivial module following a well-known common pattern, relative to the practical risk of having separate Further, this particular pattern is recommended a substantial number of places, none of which describe any such issues with it. Of course, there is the general principle of separation of concerns, and thus that entry points and package functionality should be separate (which this still fully ensures, as this module contains no non-trivial functionality beyond that necessary to serve as a single-source entrypoint for both Beyond that, the only directly relevant post I found explicitly advocating against any use of |
Original file line number | Diff line number | Diff line change | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,42 @@ | ||||||||||||||||||||||
import click | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@click.group() | ||||||||||||||||||||||
def cli(): | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
Wouldn't hurt to have this, in case we want to pass in arguments programmatically |
||||||||||||||||||||||
"""Features in support of development with QtPy.""" | ||||||||||||||||||||||
|
||||||||||||||||||||||
pass | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@cli.group() | ||||||||||||||||||||||
def mypy(): | ||||||||||||||||||||||
"""Features in support of running mypy""" | ||||||||||||||||||||||
|
||||||||||||||||||||||
pass | ||||||||||||||||||||||
|
||||||||||||||||||||||
|
||||||||||||||||||||||
@mypy.command() | ||||||||||||||||||||||
def args(): | ||||||||||||||||||||||
"""Generate command line arguments for using mypy with QtPy. | ||||||||||||||||||||||
|
||||||||||||||||||||||
This will generate strings similar to the following which help guide mypy | ||||||||||||||||||||||
through which library QtPy would have used so that mypy can get the proper | ||||||||||||||||||||||
underlying type hints. | ||||||||||||||||||||||
|
||||||||||||||||||||||
--always-false=PYQT4 --always-false=PYQT5 --always-false=PYSIDE --always-true=PYSIDE2 | ||||||||||||||||||||||
|
||||||||||||||||||||||
Use such as: | ||||||||||||||||||||||
|
||||||||||||||||||||||
env/bin/mypy --package mypackage $(env/bin/qtpy mypy args) | ||||||||||||||||||||||
""" | ||||||||||||||||||||||
|
||||||||||||||||||||||
options = {False: '--always-false', True: '--always-true'} | ||||||||||||||||||||||
|
||||||||||||||||||||||
import qtpy | ||||||||||||||||||||||
|
||||||||||||||||||||||
apis_active = {name: qtpy.API.lower() == name.lower() for name in qtpy.APIS} | ||||||||||||||||||||||
print(' '.join( | ||||||||||||||||||||||
f'{options[is_active]}={name.upper()}' | ||||||||||||||||||||||
for name, is_active | ||||||||||||||||||||||
in apis_active.items() | ||||||||||||||||||||||
)) | ||||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
A bit of boilerplate to make it a little easier to run as a script in case the user doesn't actually have QtPy installed, but rather just checked out locally There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really like encouraging not installing things. It makes it really hard to make things actually work. And why the indirection through There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good points, agreed this isn't necessary or desirable. FWIW, if I'd started this package from scratch, I'd have put the top-level package inside a
Just convention, and probably a foolish one, at least in this case where it doesn't do anything special.
I assume its a moot point, but I'm curious as to the need for |
Original file line number | Diff line number | Diff line change | ||||||||
---|---|---|---|---|---|---|---|---|---|---|
@@ -0,0 +1,45 @@ | ||||||||||
from __future__ import absolute_import | ||||||||||
|
||||||||||
import subprocess | ||||||||||
import sys | ||||||||||
|
||||||||||
import pytest | ||||||||||
|
||||||||||
import qtpy | ||||||||||
|
||||||||||
|
||||||||||
subcommands = [ | ||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
As a top-level constant, shouldn't this be ALL_CAPS? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Many people do that. I don't like it. No need to be YELLING. I presume it will get changed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Given Python has no runtime enforcement of constants staying constants, particularly for mutable objects like this list here which are effectively global state, it is particularly important to clearly distinguish them from regular variables. |
||||||||||
['mypy'], | ||||||||||
['mypy', 'args'], | ||||||||||
] | ||||||||||
|
||||||||||
|
||||||||||
@pytest.mark.parametrize( | ||||||||||
argnames=['subcommand'], | ||||||||||
argvalues=[[subcommand] for subcommand in subcommands], | ||||||||||
ids=[' '.join(subcommand) for subcommand in subcommands], | ||||||||||
Comment on lines
+19
to
+20
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
To match previous |
||||||||||
) | ||||||||||
def test_cli_help_does_not_fail(subcommand): | ||||||||||
# .check_call() over .run(..., check=True) because of py2 | ||||||||||
subprocess.check_call( | ||||||||||
[sys.executable, '-m', 'qtpy', *subcommand, '--help'], | ||||||||||
) | ||||||||||
|
||||||||||
|
||||||||||
def test_cli_mypy_args(): | ||||||||||
output = subprocess.check_output( | ||||||||||
[sys.executable, '-m', 'qtpy', 'mypy', 'args'], | ||||||||||
) | ||||||||||
|
||||||||||
if qtpy.PYQT4: | ||||||||||
expected = b'--always-true=PYQT4 --always-false=PYQT5 --always-false=PYSIDE --always-false=PYSIDE2\n' | ||||||||||
elif qtpy.PYQT5: | ||||||||||
expected = b'--always-false=PYQT4 --always-true=PYQT5 --always-false=PYSIDE --always-false=PYSIDE2\n' | ||||||||||
elif qtpy.PYSIDE: | ||||||||||
expected = b'--always-false=PYQT4 --always-false=PYQT5 --always-true=PYSIDE --always-false=PYSIDE2\n' | ||||||||||
elif qtpy.PYSIDE2: | ||||||||||
expected = b'--always-false=PYQT4 --always-false=PYQT5 --always-false=PYSIDE --always-true=PYSIDE2\n' | ||||||||||
else: | ||||||||||
assert False, 'No valid API to test' | ||||||||||
|
||||||||||
assert output == expected |
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -47,5 +47,8 @@ | |||||
'Programming Language :: Python :: 3', | ||||||
'Programming Language :: Python :: 3.3', | ||||||
'Programming Language :: Python :: 3.4', | ||||||
'Programming Language :: Python :: 3.5'] | ||||||
'Programming Language :: Python :: 3.5'], | ||||||
extras_require={'cli': ['click']}, | ||||||
entry_points={'console_scripts': 'qtpy = qtpy.cli:cli [cli]'}, | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
I've usually pointed my top-level entry point directly at There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This demands a whole turn around that includes some icky stuff I'd rather just avoid. Not worth maybe having to update an entry point someday, maybe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm a little confused with how changing a few characters here and adding a couple lines of standard boilerplate to |
||||||
include_package_data=True | ||||||
) |
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.
Fix some grammar and syntax issues and a run-on sentence, and a few diction refinements
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.
That's not really the message here though. Isolating out the middle bit doesn't help. I'll take a pass at improving this.
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.
Sorry if I've impaired the meaning, I was trying to break up a long run-on sentence and not have the "similar to the following" be disconnected from said "following". Your new revision looks much better than either, so we can go from there, thanks.