Skip to content

Create mypy_extensions package.#2228

Merged
gvanrossum merged 2 commits into
python:masterfrom
davidfstr:ext
Oct 15, 2016
Merged

Create mypy_extensions package.#2228
gvanrossum merged 2 commits into
python:masterfrom
davidfstr:ext

Conversation

@davidfstr

Copy link
Copy Markdown
Contributor

See discussion here: #2210

Comment thread extensions/setup.py
scripts=[],
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']),
classifiers=mypy_setup.setup_kwargs['classifiers'],
)

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

Comment thread extensions/mypy_extensions/typing.py Outdated

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)

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

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.

Comment thread mypy/git.py Outdated
@@ -1,18 +1,28 @@
"""Utilities for verifying git integrity."""

from __future__ import print_function

Copy link
Copy Markdown
Contributor Author

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

@gvanrossum gvanrossum Oct 10, 2016

Copy link
Copy Markdown
Member

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.

Comment thread extensions/setup.py Outdated
packages=['mypy_extensions'],
scripts=[],
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']),
classifiers=mypy_setup.setup_kwargs['classifiers'],

Copy link
Copy Markdown
Contributor Author

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.

Copy link
Copy Markdown
Member

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...

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

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.

Comment thread extensions/mypy_extensions/typing.py Outdated
@@ -0,0 +1,18 @@
from typing import cast, Dict, Type, TypeVar

@gvanrossum gvanrossum Oct 10, 2016

Copy link
Copy Markdown
Member

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).

Comment thread extensions/mypy_extensions/typing.py Outdated
@@ -0,0 +1,18 @@
from typing import cast, Dict, Type, TypeVar


Copy link
Copy Markdown
Member

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.

Comment thread extensions/mypy_extensions/typing.py Outdated

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)

Copy link
Copy Markdown
Member

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.

Comment thread extensions/setup.py Outdated
import sys

if '..' not in sys.path:
sys.path.insert(0, '..')

Copy link
Copy Markdown
Member

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.

Comment thread extensions/setup.py Outdated

if '..' not in sys.path:
sys.path.insert(0, '..')
import setup as mypy_setup

Copy link
Copy Markdown
Member

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.

Comment thread extensions/setup.py Outdated
packages=['mypy_extensions'],
scripts=[],
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']),
classifiers=mypy_setup.setup_kwargs['classifiers'],

Copy link
Copy Markdown
Member

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...

Comment thread extensions/setup.py
scripts=[],
data_files=mypy_setup.find_data_files('mypy_extensions', ['*.py', '*.pyi']),
classifiers=mypy_setup.setup_kwargs['classifiers'],
)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good call.

Comment thread mypy/git.py Outdated
@@ -1,18 +1,28 @@
"""Utilities for verifying git integrity."""

from __future__ import print_function

@gvanrossum gvanrossum Oct 10, 2016

Copy link
Copy Markdown
Member

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.

Comment thread mypy/git.py Outdated
# NOTE: Cannot use typing.TYPE_CHECKING guard here because cannot import
# "typing" in this file at all.
if False:
from typing import Iterator

Copy link
Copy Markdown
Member

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.

Comment thread setup.py Outdated
)

if __name__ == '__main__':
setup(**setup_kwargs)

Copy link
Copy Markdown
Member

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.

@davidfstr

davidfstr commented Oct 11, 2016

Copy link
Copy Markdown
Contributor Author

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 if __name__ == '__main__' in setup.py, which may not even work.

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.


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.

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 typing module (as opposed to the one in the stdlib). Then we could add experimental extensions directly, although it still feels a little weird to be putting experimental extensions in typing.


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.

Perhaps mypy_extensions.mypy_typing as an alternate name. Here's some potential usage patterns:

from mypy_extensions.mypy_typing import TypedDict
Point = TypedDict('Point', dict(x=int, y=int))
from mypy_extensions import mypy_typing
Point = mypy_typing.TypedDict('Point', dict(x=int, y=int))

@JukkaL

JukkaL commented Oct 11, 2016

Copy link
Copy Markdown
Collaborator

Why not just from mypy_extensions import TypedDict? I wonder if this is what Guido suggested.

I don't think that mypy_extensions should depend on anything currently in setup.py or mypy/git.py. Let's just keep the codebases separate -- the little sharing we could have is not worth the extra complexity and loss of flexibility. The git checks aren't relevant here, as they are primarily for typeshed, and mypy_extensions doesn't need it.

So here's how this would look better to me:

  • Only add new files mypy_extensions/mypy_extensions.py and mypy_extensions/setup.py (+ perhaps a readme and tests).
  • setup.py can be minimal. Here's an example for typing that is comparable, as it only installs a single file: https://github.com/python/typing/blob/master/setup.py
  • If we need separate implementations for Python 2 and 3, maybe have mypy_extensions/2.7 and mypy_extensions/3 subdirectories. However, perhaps a single implementation is sufficient, at least for now.
  • Version mypy_extensions independently of mypy.

@gvanrossum

gvanrossum commented Oct 11, 2016 via email

Copy link
Copy Markdown
Member

@davidfstr

Copy link
Copy Markdown
Contributor Author

Sounds good. I'll see about another iteration some time this week.

@davidfstr

Copy link
Copy Markdown
Contributor Author

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.

@gvanrossum gvanrossum left a comment

Copy link
Copy Markdown
Member

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!

Comment thread extensions/setup.py Outdated
'Topic :: Software Development',
]

classifiers = _mypy_classifiers + [

Copy link
Copy Markdown
Member

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.

@davidfstr

Copy link
Copy Markdown
Contributor Author

Feedback integrated.

@gvanrossum gvanrossum merged commit 47b1d6a into python:master Oct 15, 2016
@gvanrossum

Copy link
Copy Markdown
Member

Thanks for your patience! I really like the simplicity of the result.

@davidfstr

Copy link
Copy Markdown
Contributor Author

Sure. These things take time.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants