-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Create mypy_extensions package. #2228
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
Conversation
scripts=[], | ||
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']), | ||
classifiers=mypy_setup.setup_kwargs['classifiers'], | ||
) |
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.
This setup() call has all the same keys as the one in setup.py for mypy with one exception: There is no cmdclass
key. I wasn't able to prove that it made sense here, so I did not include it.
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.
Good call.
|
||
new_dict.__name__ = typename # type: ignore # https://github.com/python/mypy/issues/708 | ||
new_dict.__supertype__ = dict # type: ignore # https://github.com/python/mypy/issues/708 | ||
return cast(Type[dict], new_dict) |
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.
If we don't want to add anything to mypy_extensions/typing.py
initially, deferring to #2206 , we could blank it out.
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.
I think it would be better to leave this empty for now.
@@ -1,18 +1,28 @@ | |||
"""Utilities for verifying git integrity.""" | |||
|
|||
from __future__ import print_function |
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.
This module must now support running in a Python 2.x context so that python setup.py
in mypy_extensions works.
/mypy_extensions/setup.py --> /setup.py --> mypy/git.py
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.
You need at least a comment reminding the reader. It would also be nice if the unit tests somehow enforced this. (If someone accidentally breaks this and the tests don't catch it, it's a real problem.)
But honestly I would much prefer if the setup.py for mypy_extensions didn't depend on this module at all.
packages=['mypy_extensions'], | ||
scripts=[], | ||
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']), | ||
classifiers=mypy_setup.setup_kwargs['classifiers'], |
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.
It occurs to me that at least 'Programming Language :: Python :: 2' should probably be added to the classifiers for mypy_extensions.
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.
Yeah, though I'm not sure whether anything actually checks those...
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 for saying the same thing in seven different ways... I feel quite strongly about not complexificating setup files.
@@ -0,0 +1,18 @@ | |||
from typing import cast, Dict, Type, TypeVar |
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.
The more I think about the less I like that this module is named "typing.py". Yes, it's in a module namespace, but many people will probably prefer to write "from mypy_extensions import typing" and then use e.g. "typing.TypedDict", but if they also write "import typing" they have a name clash. And even if they don't it might confuse human readers to see "typing.TypedDict" (e.g. when using an IDE that hides the imports). Better not to invite confusion and give this a different name.
And honestly I also more and more believe that making this a package is over-engineering it. The cost of making it a package in the future are slight, and the probability that we'll never need that is high.
Also we need a module docstring and probably a comment explaining that cast..TypeVar are not intended to be exported.
Come to think of it, maybe we should just add a .pyi file adjacent with the signatures, and remove any type annotations from this file. In my experience with the actual top-level typing.py, I've found that the code implementing this doesn't benefit much from being type-checked itself, and there's a real cost (e.g. cast() is a pure-Python function and calling it is not particualrly cheap).
@@ -0,0 +1,18 @@ | |||
from typing import cast, Dict, Type, TypeVar | |||
|
|||
|
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.
Don't need two blank lines here.
|
||
new_dict.__name__ = typename # type: ignore # https://github.com/python/mypy/issues/708 | ||
new_dict.__supertype__ = dict # type: ignore # https://github.com/python/mypy/issues/708 | ||
return cast(Type[dict], new_dict) |
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.
I think it would be better to leave this empty for now.
import sys | ||
|
||
if '..' not in sys.path: | ||
sys.path.insert(0, '..') |
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.
Have you tested this much with different installers (e.g. "python setup.py" as well as "pip install ")?
sys.path manipulations in a setup.py file give me the heebie-jeebies.
|
||
if '..' not in sys.path: | ||
sys.path.insert(0, '..') | ||
import setup as mypy_setup |
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.
This (importing the top-level setup.py) also scares the living daylight out of me.
Most setup.py files are purely cargo-culted and work by accident.
packages=['mypy_extensions'], | ||
scripts=[], | ||
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']), | ||
classifiers=mypy_setup.setup_kwargs['classifiers'], |
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.
Yeah, though I'm not sure whether anything actually checks those...
scripts=[], | ||
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']), | ||
classifiers=mypy_setup.setup_kwargs['classifiers'], | ||
) |
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.
Good call.
@@ -1,18 +1,28 @@ | |||
"""Utilities for verifying git integrity.""" | |||
|
|||
from __future__ import print_function |
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.
You need at least a comment reminding the reader. It would also be nice if the unit tests somehow enforced this. (If someone accidentally breaks this and the tests don't catch it, it's a real problem.)
But honestly I would much prefer if the setup.py for mypy_extensions didn't depend on this module at all.
# NOTE: Cannot use typing.TYPE_CHECKING guard here because cannot import | ||
# "typing" in this file at all. | ||
if False: | ||
from typing import Iterator |
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.
I prefer this:
MYPY = False
if MYPY:
from typing import Iterator
We'll have to support MYPY basically forever, while "if False" might eventually cause the body to be considered unreachable.
) | ||
|
||
if __name__ == '__main__': | ||
setup(**setup_kwargs) |
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.
Oh, I don't like this at all. All this linkage between setup.py and extensions/setup.py is just extremely fragile.
I hear you loud and clear to be gentle with setup.py files. Here's a different approach: Instead of having /mypy_extensions/setup.py depend directly on /setup.py, have both of them depend on a simpler shared module. Perhaps /mypy_extensions/setup_common.py . No more black magic with sys.path. No more Additionally mypy/git.py would be moved into this shared module since only the setup.py files use it. (There is an import in mypy/main.py but it is unused.) Can't remove the dependence entirely since the module version number is computed with git. Since mypy.git feels like an internal module (and therefore not part of the mypy API) I believe it should be safe to move without breaking external code.
Did you have another approach in mind for having experimental extensions to mypy? It's not clear to me what other less-engineered approaches would work. ...unless we actually have control over the 3rd party
Perhaps
|
Why not just I don't think that So here's how this would look better to me:
|
Amen.
|
Sounds good. I'll see about another iteration some time this week. |
I've pushed a significantly leaner version of this package for review. I've left mypy_extensions.py empty for the time being. If the thrust of this PR is generally good I might opt to merge it with #2206 so that I can actually put something in mypy_extensions, namely TypedDict. |
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! I think the classifiers could be simpler, and can you please add a comment explaining what this is to mypy_extensions.py? Would also be handy if it said explicitly it has to be compatible with Python 2 and 3. Once you've got those two I'm ready to merge!
'Topic :: Software Development', | ||
] | ||
|
||
classifiers = _mypy_classifiers + [ |
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.
I see no reason not to make this into a single longer list.
Feedback integrated. |
Thanks for your patience! I really like the simplicity of the result. |
Sure. These things take time. |
See discussion here: #2210