validators.py 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. """
  2. Commonly useful validators.
  3. """
  4. from __future__ import absolute_import, division, print_function
  5. from ._make import _AndValidator, and_, attrib, attrs
  6. __all__ = [
  7. "and_",
  8. "in_",
  9. "instance_of",
  10. "optional",
  11. "provides",
  12. ]
  13. @attrs(repr=False, slots=True, hash=True)
  14. class _InstanceOfValidator(object):
  15. type = attrib()
  16. def __call__(self, inst, attr, value):
  17. """
  18. We use a callable class to be able to change the ``__repr__``.
  19. """
  20. if not isinstance(value, self.type):
  21. raise TypeError(
  22. "'{name}' must be {type!r} (got {value!r} that is a "
  23. "{actual!r})."
  24. .format(name=attr.name, type=self.type,
  25. actual=value.__class__, value=value),
  26. attr, self.type, value,
  27. )
  28. def __repr__(self):
  29. return (
  30. "<instance_of validator for type {type!r}>"
  31. .format(type=self.type)
  32. )
  33. def instance_of(type):
  34. """
  35. A validator that raises a :exc:`TypeError` if the initializer is called
  36. with a wrong type for this particular attribute (checks are performed using
  37. :func:`isinstance` therefore it's also valid to pass a tuple of types).
  38. :param type: The type to check for.
  39. :type type: type or tuple of types
  40. :raises TypeError: With a human readable error message, the attribute
  41. (of type :class:`attr.Attribute`), the expected type, and the value it
  42. got.
  43. """
  44. return _InstanceOfValidator(type)
  45. @attrs(repr=False, slots=True, hash=True)
  46. class _ProvidesValidator(object):
  47. interface = attrib()
  48. def __call__(self, inst, attr, value):
  49. """
  50. We use a callable class to be able to change the ``__repr__``.
  51. """
  52. if not self.interface.providedBy(value):
  53. raise TypeError(
  54. "'{name}' must provide {interface!r} which {value!r} "
  55. "doesn't."
  56. .format(name=attr.name, interface=self.interface, value=value),
  57. attr, self.interface, value,
  58. )
  59. def __repr__(self):
  60. return (
  61. "<provides validator for interface {interface!r}>"
  62. .format(interface=self.interface)
  63. )
  64. def provides(interface):
  65. """
  66. A validator that raises a :exc:`TypeError` if the initializer is called
  67. with an object that does not provide the requested *interface* (checks are
  68. performed using ``interface.providedBy(value)`` (see `zope.interface
  69. <https://zopeinterface.readthedocs.io/en/latest/>`_).
  70. :param zope.interface.Interface interface: The interface to check for.
  71. :raises TypeError: With a human readable error message, the attribute
  72. (of type :class:`attr.Attribute`), the expected interface, and the
  73. value it got.
  74. """
  75. return _ProvidesValidator(interface)
  76. @attrs(repr=False, slots=True, hash=True)
  77. class _OptionalValidator(object):
  78. validator = attrib()
  79. def __call__(self, inst, attr, value):
  80. if value is None:
  81. return
  82. self.validator(inst, attr, value)
  83. def __repr__(self):
  84. return (
  85. "<optional validator for {what} or None>"
  86. .format(what=repr(self.validator))
  87. )
  88. def optional(validator):
  89. """
  90. A validator that makes an attribute optional. An optional attribute is one
  91. which can be set to ``None`` in addition to satisfying the requirements of
  92. the sub-validator.
  93. :param validator: A validator (or a list of validators) that is used for
  94. non-``None`` values.
  95. :type validator: callable or :class:`list` of callables.
  96. .. versionadded:: 15.1.0
  97. .. versionchanged:: 17.1.0 *validator* can be a list of validators.
  98. """
  99. if isinstance(validator, list):
  100. return _OptionalValidator(_AndValidator(validator))
  101. return _OptionalValidator(validator)
  102. @attrs(repr=False, slots=True, hash=True)
  103. class _InValidator(object):
  104. options = attrib()
  105. def __call__(self, inst, attr, value):
  106. if value not in self.options:
  107. raise ValueError(
  108. "'{name}' must be in {options!r} (got {value!r})"
  109. .format(name=attr.name, options=self.options, value=value)
  110. )
  111. def __repr__(self):
  112. return (
  113. "<in_ validator with options {options!r}>"
  114. .format(options=self.options)
  115. )
  116. def in_(options):
  117. """
  118. A validator that raises a :exc:`ValueError` if the initializer is called
  119. with a value that does not belong in the options provided. The check is
  120. performed using ``value in options``.
  121. :param options: Allowed options.
  122. :type options: list, tuple, :class:`enum.Enum`, ...
  123. :raises ValueError: With a human readable error message, the attribute (of
  124. type :class:`attr.Attribute`), the expected options, and the value it
  125. got.
  126. .. versionadded:: 17.1.0
  127. """
  128. return _InValidator(options)