aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python/Automat/py3/automat/_runtimeproto.py
blob: c9c7409f5ab1025fe7bada7d7c6972822ff43564 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
"""
Workaround for U{the lack of TypeForm
<https://github.com/python/mypy/issues/9773>}.
"""

from __future__ import annotations

import sys

from typing import TYPE_CHECKING, Callable, Protocol, TypeVar

from inspect import signature, Signature

T = TypeVar("T")

ProtocolAtRuntime = Callable[[], T]


def runtime_name(x: ProtocolAtRuntime[T]) -> str:
    return x.__name__


from inspect import getmembers, isfunction

emptyProtocolMethods: frozenset[str]
if not TYPE_CHECKING:
    emptyProtocolMethods = frozenset(
        name
        for name, each in getmembers(type("Example", tuple([Protocol]), {}), isfunction)
    )


def actuallyDefinedProtocolMethods(protocol: object) -> frozenset[str]:
    """
    Attempt to ignore implementation details, and get all the methods that the
    protocol actually defines.

    that includes locally defined methods and also those defined in inherited
    superclasses.
    """
    return (
        frozenset(name for name, each in getmembers(protocol, isfunction))
        - emptyProtocolMethods
    )


def _fixAnnotation(method: Callable[..., object], it: object, ann: str) -> None:
    annotation = getattr(it, ann)
    if isinstance(annotation, str):
        setattr(it, ann, eval(annotation, method.__globals__))


def _liveSignature(method: Callable[..., object]) -> Signature:
    """
    Get a signature with evaluated annotations.
    """
    # TODO: could this be replaced with get_type_hints?
    result = signature(method)
    for param in result.parameters.values():
        _fixAnnotation(method, param, "_annotation")
    _fixAnnotation(method, result, "_return_annotation")
    return result