Why does the docs example for ParamSpec use collections.abc.Callable?

I am so happy that it’s possible to type decorators nicely now. But I noticed the docs for ParamSpec give this example:

from collections.abc import Callable
from typing import TypeVar, ParamSpec
import logging

T = TypeVar('T')
P = ParamSpec('P')

def add_logging(f: Callable[P, T]) -> Callable[P, T]:
    '''A type-safe decorator to add logging to a function.'''
    def inner(*args: P.args, **kwargs: P.kwargs) -> T:
        logging.info(f'{f.__name__} was called')
        return f(*args, **kwargs)
    return inner

@add_logging
def add_two(x: float, y: float) -> float:
    '''Add two numbers together.'''
    return x + y

And it made me wonder… is there a reason that from collections.abc import Callable is used instead of from typing import Callable?

Is the latter deprecated now?

According to the Python documentation typing.Callable is deprecated since Python 3.9 due to the PEP 585 – Type Hinting Generics In Standard Collections. In resume the PEP proposes to allow Generics in the standard collections[1] to remove the need to maintain a parallel type hierarchy in the typing module [2].

Although is indeed odd the documentation mentioning the change in the deprecated “typing.Callable”.

2 Likes

Good to know - it is totally deliberate :slight_smile:

and I guess it makes sense that the typing.Callable docs are where it says that it’s deprecated