variadic.py 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. from .utils import typename
  2. __all__ = ["VariadicSignatureType", "isvariadic", "VariadicSignatureMeta", "Variadic"]
  3. class VariadicSignatureType(type):
  4. # checking if subclass is a subclass of self
  5. def __subclasscheck__(cls, subclass):
  6. other_type = (subclass.variadic_type if isvariadic(subclass)
  7. else (subclass,))
  8. return subclass is cls or all(
  9. issubclass(other, cls.variadic_type) for other in other_type # type: ignore[attr-defined]
  10. )
  11. def __eq__(cls, other):
  12. """
  13. Return True if other has the same variadic type
  14. Parameters
  15. ----------
  16. other : object (type)
  17. The object (type) to check
  18. Returns
  19. -------
  20. bool
  21. Whether or not `other` is equal to `self`
  22. """
  23. return (isvariadic(other) and
  24. set(cls.variadic_type) == set(other.variadic_type)) # type: ignore[attr-defined]
  25. def __hash__(cls):
  26. return hash((type(cls), frozenset(cls.variadic_type))) # type: ignore[attr-defined]
  27. def isvariadic(obj):
  28. """Check whether the type `obj` is variadic.
  29. Parameters
  30. ----------
  31. obj : type
  32. The type to check
  33. Returns
  34. -------
  35. bool
  36. Whether or not `obj` is variadic
  37. Examples
  38. --------
  39. >>> # xdoctest: +SKIP
  40. >>> isvariadic(int)
  41. False
  42. >>> isvariadic(Variadic[int])
  43. True
  44. """
  45. return isinstance(obj, VariadicSignatureType)
  46. class VariadicSignatureMeta(type):
  47. """A metaclass that overrides ``__getitem__`` on the class. This is used to
  48. generate a new type for Variadic signatures. See the Variadic class for
  49. examples of how this behaves.
  50. """
  51. def __getitem__(cls, variadic_type):
  52. if not (isinstance(variadic_type, (type, tuple)) or type(variadic_type)):
  53. raise ValueError("Variadic types must be type or tuple of types"
  54. " (Variadic[int] or Variadic[(int, float)]")
  55. if not isinstance(variadic_type, tuple):
  56. variadic_type = variadic_type,
  57. return VariadicSignatureType(
  58. 'Variadic[%s]' % typename(variadic_type),
  59. (),
  60. dict(variadic_type=variadic_type, __slots__=())
  61. )
  62. class Variadic(metaclass=VariadicSignatureMeta):
  63. """A class whose getitem method can be used to generate a new type
  64. representing a specific variadic signature.
  65. Examples
  66. --------
  67. >>> # xdoctest: +SKIP
  68. >>> Variadic[int] # any number of int arguments
  69. <class 'multipledispatch.variadic.Variadic[int]'>
  70. >>> Variadic[(int, str)] # any number of one of int or str arguments
  71. <class 'multipledispatch.variadic.Variadic[(int, str)]'>
  72. >>> issubclass(int, Variadic[int])
  73. True
  74. >>> issubclass(int, Variadic[(int, str)])
  75. True
  76. >>> issubclass(str, Variadic[(int, str)])
  77. True
  78. >>> issubclass(float, Variadic[(int, str)])
  79. False
  80. """