-
-
Notifications
You must be signed in to change notification settings - Fork 1.7k
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
redo type annotations #1995
Merged
Merged
redo type annotations #1995
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@davidism it looks like you could backport the 3.9 if TYPE_CHECKING:
from typing import Generic
else:
from .compat import Generic |
Thanks, but I'm not interested in maintaining compat files anymore. See: removal of Python 2. All that does is mean I have to pull in code that's not about Werkzeug, then keep track of removing it years later, and make sure it keeps working with Mypy and other tools in the mean time. |
pgjones
reviewed
Jan 10, 2021
bjgill
added a commit
to bjgill/werkzeug
that referenced
this pull request
Jan 26, 2021
In pallets#1995, typing was added to large parts of this project. This will be really useful to me. One of the problems I have with the latest release is `abort`. PyCharm doesn't know that `abort` aborts. So it will complain about possibly uninitialised variables if I write code like this: ``` if foo: bar = 1 else: abort(404) print(bar) ``` In master, `abort` now returns type `None`: `def abort(status: t.Union[int, "Response"], *args, **kwargs) -> None:` This type annotation means that the function returns `None`. This is not the case - I think `abort` always raises an exception. Instead, what we want to do is change the return type to [`t.NoReturn`](https://www.python.org/dev/peps/pep-0484/#the-noreturn-type). This expresses the correct meaning, which is that the `abort` function never returns. In turn, this will help PyCharm and other analysers understand code that uses `abort` better.
4 tasks
bjgill
added a commit
to bjgill/werkzeug
that referenced
this pull request
Jan 26, 2021
In pallets#1995, typing was added to large parts of this project. This will be really useful to me. One of the problems I have with the latest release is `abort`. PyCharm doesn't know that `abort` aborts. So it will complain about possibly uninitialised variables if I write code like this: ``` if foo: bar = 1 else: abort(404) print(bar) ``` In master, `abort` now returns type `None`: `def abort(status: t.Union[int, "Response"], *args, **kwargs) -> None:` This type annotation means that the function returns `None`. This is not the case - I think `abort` always raises an exception. Instead, what we want to do is change the return type to [`t.NoReturn`](https://www.python.org/dev/peps/pep-0484/#the-noreturn-type). This expresses the correct meaning, which is that the `abort` function never returns. In turn, this will help PyCharm and other analysers understand code that uses `abort` better.
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Rewrite the type annotations by hand. The previous annotations generated from MonkeyType were too inaccurate, and trying to modify them after the fact was frustrating, as fixing one part would cause errors in others. Wrote a RedBaron script to remove all existing annotations.
Tried to enable as many Mypy checks as possible, but had to make some compromises in the interest of time. Mypy is nice overall, but it has a lot of corner cases or unimplemented features that Werkzeug's code seems to trigger quite a lot. This can be addressed by future contributors.
allow_redefinition
should be removed.disallow_untyped_defs
anddisallow_incomplete_defs
should be enabled (although can be disabled for tests).warn_return_any
should be enabled.no_implicit_reexport
should be enabled.Any
should be enabledtype: ignore
comments andcast()
calls as possible. Ignore comments can hide other issues on the same line.I tried to modify as little code as possible (besides the annotations). Occasionally I had to rewrite an instance or none check, or rename variables to avoid redefinition. There were a few places that typing seemed to catch a legitimate bug (such as calling
dict.get
and gettingNone
). All tests still pass.I removed the
werkzeug.types
module, as it didn't end up being necessary. I importedtyping as t
to make the annotations shorter (t.Optional
instead oftyping.Optional
). That also avoids importing a ton of names fromtyping
into every module. Typeshed provides awsgiref.types
stub that came in handy for annotating WSGI environs and callables. Flake8 (through PyFlakes) doesn't understand@t.overload
, it only understands@typing.overload
(PyCQA/pyflakes#561), so in some files there's bothimport typing
andimport typing as t
.Inheriting from
typing.Generic
makes instantiation many times slower until Python 3.9. This is unacceptable for Werkzeug where I estimate ~10 are created per request. I wanted the data structures to be generic, so that code is typed in a stubpyi
file instead. Unfortunately, that disables all type checking on thepy
file and only consider thepyi
file (python/mypy#5028), so there was no type checking done on thedatastructures.py
code itself. I considered this acceptable, as I already know Werkzeug's code is passing tests, and I'd rather be able to doMultiDict[str, str]
in user code instead.Much of the complexity came from Werkzeug allowing both str and bytes in many places, even where it no longer makes much sense since Python 2 compatibility is gone. Additionally, there are some odd code paths that don't appear to be used anywhere. Should look at deprecating these types of things in a future release.