Proposed PEP 484 addition: describe a way of annotating decorated declarations

There's a PR to the peps proposal here: https://github.com/python/peps/pull/242 The full text of the current proposal is below. The motivation for this is that for complex decorators, even if the type checker can figure out what's going on (by taking the signature of the decorator into account), it's sometimes helpful to the human reader of the code to be reminded of the type after applying the decorators (or a stack thereof). Much discussion can be found in the PR. Note that we ended up having `Callable` in the type because there's no rule that says a decorator returns a function type (e.g. `property` doesn't). This is a small thing but I'd like to run it by a larger audience than the core mypy devs who have commented so far. Here's the proposed text (wordsmithing suggestions in the PR please): +Decorators +---------- + +Decorators can modify the types of the functions or classes they +decorate. Use the ``decorated_type`` decorator to declare the type of +the resulting item after all other decorators have been applied:: + + from typing import ContextManager, Iterator, decorated_type + from contextlib import contextmanager + + class DatabaseSession: ... + + @decorated_type(Callable[[str], ContextManager[DatabaseSession]]) + @contextmanager + def session(url: str) -> Iterator[DatabaseSession]: + s = DatabaseSession(url) + try: + yield s + finally: + s.close() + +The argument of ``decorated_type`` is a type annotation on the name +being declared (``session``, in the example above). If you have +multiple decorators, ``decorated_type`` must be topmost. The +``decorated_type`` decorator is invalid on a function declaration that +is also decorated with ``overload``, but you can annotate the +implementation of the overload series with ``decorated_type``. + -- --Guido van Rossum (python.org/~guido <http://python.org/%7Eguido>)

On 1 May 2017 at 03:07, Guido van Rossum <guido@python.org> wrote:
So a rigorous typechecker that understood the full decorator stack would be able to check whether or not the argument to `decorated_type` was correct, while all typecheckers (and human readers) would be able to just believe the argument rather than having to run through all the decorator transformations? Make sense to me. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Mon, May 1, 2017 at 12:28 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Yes. In fact the intention is that the checker should check the declared type with the inferred and complain if they don't fit. In some cases the inferred type would have `Any` where the declared type would have a specific type and then the declared type would "win" (for uses of the decorated function) -- this is an example of where "erosion" in type inference can be counteracted by explicit declarations. -- --Guido van Rossum (python.org/~guido)

On 1 May 2017 at 03:07, Guido van Rossum <guido@python.org> wrote:
So a rigorous typechecker that understood the full decorator stack would be able to check whether or not the argument to `decorated_type` was correct, while all typecheckers (and human readers) would be able to just believe the argument rather than having to run through all the decorator transformations? Make sense to me. Cheers, Nick. -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

On Mon, May 1, 2017 at 12:28 AM, Nick Coghlan <ncoghlan@gmail.com> wrote:
Yes. In fact the intention is that the checker should check the declared type with the inferred and complain if they don't fit. In some cases the inferred type would have `Any` where the declared type would have a specific type and then the declared type would "win" (for uses of the decorated function) -- this is an example of where "erosion" in type inference can be counteracted by explicit declarations. -- --Guido van Rossum (python.org/~guido)
participants (2)
-
Guido van Rossum
-
Nick Coghlan