_runtimeproto.py 1.6 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. """
  2. Workaround for U{the lack of TypeForm
  3. <https://github.com/python/mypy/issues/9773>}.
  4. """
  5. from __future__ import annotations
  6. import sys
  7. from typing import TYPE_CHECKING, Callable, Protocol, TypeVar
  8. from inspect import signature, Signature
  9. T = TypeVar("T")
  10. ProtocolAtRuntime = Callable[[], T]
  11. def runtime_name(x: ProtocolAtRuntime[T]) -> str:
  12. return x.__name__
  13. from inspect import getmembers, isfunction
  14. emptyProtocolMethods: frozenset[str]
  15. if not TYPE_CHECKING:
  16. emptyProtocolMethods = frozenset(
  17. name
  18. for name, each in getmembers(type("Example", tuple([Protocol]), {}), isfunction)
  19. )
  20. def actuallyDefinedProtocolMethods(protocol: object) -> frozenset[str]:
  21. """
  22. Attempt to ignore implementation details, and get all the methods that the
  23. protocol actually defines.
  24. that includes locally defined methods and also those defined in inherited
  25. superclasses.
  26. """
  27. return (
  28. frozenset(name for name, each in getmembers(protocol, isfunction))
  29. - emptyProtocolMethods
  30. )
  31. def _fixAnnotation(method: Callable[..., object], it: object, ann: str) -> None:
  32. annotation = getattr(it, ann)
  33. if isinstance(annotation, str):
  34. setattr(it, ann, eval(annotation, method.__globals__))
  35. def _liveSignature(method: Callable[..., object]) -> Signature:
  36. """
  37. Get a signature with evaluated annotations.
  38. """
  39. # TODO: could this be replaced with get_type_hints?
  40. result = signature(method)
  41. for param in result.parameters.values():
  42. _fixAnnotation(method, param, "_annotation")
  43. _fixAnnotation(method, result, "_return_annotation")
  44. return result