You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

252 lines
7.5 KiB

4 years ago
  1. from typing import (
  2. Any,
  3. Callable,
  4. Dict,
  5. Generic,
  6. List,
  7. Optional,
  8. Sequence,
  9. Mapping,
  10. Tuple,
  11. Type,
  12. TypeVar,
  13. Union,
  14. overload,
  15. )
  16. # `import X as X` is required to make these public
  17. from . import exceptions as exceptions
  18. from . import filters as filters
  19. from . import converters as converters
  20. from . import validators as validators
  21. _T = TypeVar("_T")
  22. _C = TypeVar("_C", bound=type)
  23. _ValidatorType = Callable[[Any, Attribute, _T], Any]
  24. _ConverterType = Callable[[Any], _T]
  25. _FilterType = Callable[[Attribute, Any], bool]
  26. # FIXME: in reality, if multiple validators are passed they must be in a list or tuple,
  27. # but those are invariant and so would prevent subtypes of _ValidatorType from working
  28. # when passed in a list or tuple.
  29. _ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]]
  30. # _make --
  31. NOTHING: object
  32. # NOTE: Factory lies about its return type to make this possible: `x: List[int] = Factory(list)`
  33. # Work around mypy issue #4554 in the common case by using an overload.
  34. @overload
  35. def Factory(factory: Callable[[], _T]) -> _T: ...
  36. @overload
  37. def Factory(
  38. factory: Union[Callable[[Any], _T], Callable[[], _T]],
  39. takes_self: bool = ...,
  40. ) -> _T: ...
  41. class Attribute(Generic[_T]):
  42. name: str
  43. default: Optional[_T]
  44. validator: Optional[_ValidatorType[_T]]
  45. repr: bool
  46. cmp: bool
  47. hash: Optional[bool]
  48. init: bool
  49. converter: Optional[_ConverterType[_T]]
  50. metadata: Dict[Any, Any]
  51. type: Optional[Type[_T]]
  52. kw_only: bool
  53. def __lt__(self, x: Attribute) -> bool: ...
  54. def __le__(self, x: Attribute) -> bool: ...
  55. def __gt__(self, x: Attribute) -> bool: ...
  56. def __ge__(self, x: Attribute) -> bool: ...
  57. # NOTE: We had several choices for the annotation to use for type arg:
  58. # 1) Type[_T]
  59. # - Pros: Handles simple cases correctly
  60. # - Cons: Might produce less informative errors in the case of conflicting TypeVars
  61. # e.g. `attr.ib(default='bad', type=int)`
  62. # 2) Callable[..., _T]
  63. # - Pros: Better error messages than #1 for conflicting TypeVars
  64. # - Cons: Terrible error messages for validator checks.
  65. # e.g. attr.ib(type=int, validator=validate_str)
  66. # -> error: Cannot infer function type argument
  67. # 3) type (and do all of the work in the mypy plugin)
  68. # - Pros: Simple here, and we could customize the plugin with our own errors.
  69. # - Cons: Would need to write mypy plugin code to handle all the cases.
  70. # We chose option #1.
  71. # `attr` lies about its return type to make the following possible:
  72. # attr() -> Any
  73. # attr(8) -> int
  74. # attr(validator=<some callable>) -> Whatever the callable expects.
  75. # This makes this type of assignments possible:
  76. # x: int = attr(8)
  77. #
  78. # This form catches explicit None or no default but with no other arguments returns Any.
  79. @overload
  80. def attrib(
  81. default: None = ...,
  82. validator: None = ...,
  83. repr: bool = ...,
  84. cmp: bool = ...,
  85. hash: Optional[bool] = ...,
  86. init: bool = ...,
  87. convert: None = ...,
  88. metadata: Optional[Mapping[Any, Any]] = ...,
  89. type: None = ...,
  90. converter: None = ...,
  91. factory: None = ...,
  92. kw_only: bool = ...,
  93. ) -> Any: ...
  94. # This form catches an explicit None or no default and infers the type from the other arguments.
  95. @overload
  96. def attrib(
  97. default: None = ...,
  98. validator: Optional[_ValidatorArgType[_T]] = ...,
  99. repr: bool = ...,
  100. cmp: bool = ...,
  101. hash: Optional[bool] = ...,
  102. init: bool = ...,
  103. convert: Optional[_ConverterType[_T]] = ...,
  104. metadata: Optional[Mapping[Any, Any]] = ...,
  105. type: Optional[Type[_T]] = ...,
  106. converter: Optional[_ConverterType[_T]] = ...,
  107. factory: Optional[Callable[[], _T]] = ...,
  108. kw_only: bool = ...,
  109. ) -> _T: ...
  110. # This form catches an explicit default argument.
  111. @overload
  112. def attrib(
  113. default: _T,
  114. validator: Optional[_ValidatorArgType[_T]] = ...,
  115. repr: bool = ...,
  116. cmp: bool = ...,
  117. hash: Optional[bool] = ...,
  118. init: bool = ...,
  119. convert: Optional[_ConverterType[_T]] = ...,
  120. metadata: Optional[Mapping[Any, Any]] = ...,
  121. type: Optional[Type[_T]] = ...,
  122. converter: Optional[_ConverterType[_T]] = ...,
  123. factory: Optional[Callable[[], _T]] = ...,
  124. kw_only: bool = ...,
  125. ) -> _T: ...
  126. # This form covers type=non-Type: e.g. forward references (str), Any
  127. @overload
  128. def attrib(
  129. default: Optional[_T] = ...,
  130. validator: Optional[_ValidatorArgType[_T]] = ...,
  131. repr: bool = ...,
  132. cmp: bool = ...,
  133. hash: Optional[bool] = ...,
  134. init: bool = ...,
  135. convert: Optional[_ConverterType[_T]] = ...,
  136. metadata: Optional[Mapping[Any, Any]] = ...,
  137. type: object = ...,
  138. converter: Optional[_ConverterType[_T]] = ...,
  139. factory: Optional[Callable[[], _T]] = ...,
  140. kw_only: bool = ...,
  141. ) -> Any: ...
  142. @overload
  143. def attrs(
  144. maybe_cls: _C,
  145. these: Optional[Dict[str, Any]] = ...,
  146. repr_ns: Optional[str] = ...,
  147. repr: bool = ...,
  148. cmp: bool = ...,
  149. hash: Optional[bool] = ...,
  150. init: bool = ...,
  151. slots: bool = ...,
  152. frozen: bool = ...,
  153. weakref_slot: bool = ...,
  154. str: bool = ...,
  155. auto_attribs: bool = ...,
  156. kw_only: bool = ...,
  157. cache_hash: bool = ...,
  158. ) -> _C: ...
  159. @overload
  160. def attrs(
  161. maybe_cls: None = ...,
  162. these: Optional[Dict[str, Any]] = ...,
  163. repr_ns: Optional[str] = ...,
  164. repr: bool = ...,
  165. cmp: bool = ...,
  166. hash: Optional[bool] = ...,
  167. init: bool = ...,
  168. slots: bool = ...,
  169. frozen: bool = ...,
  170. weakref_slot: bool = ...,
  171. str: bool = ...,
  172. auto_attribs: bool = ...,
  173. kw_only: bool = ...,
  174. cache_hash: bool = ...,
  175. ) -> Callable[[_C], _C]: ...
  176. # TODO: add support for returning NamedTuple from the mypy plugin
  177. class _Fields(Tuple[Attribute, ...]):
  178. def __getattr__(self, name: str) -> Attribute: ...
  179. def fields(cls: type) -> _Fields: ...
  180. def fields_dict(cls: type) -> Dict[str, Attribute]: ...
  181. def validate(inst: Any) -> None: ...
  182. # TODO: add support for returning a proper attrs class from the mypy plugin
  183. # we use Any instead of _CountingAttr so that e.g. `make_class('Foo', [attr.ib()])` is valid
  184. def make_class(
  185. name: str,
  186. attrs: Union[List[str], Tuple[str, ...], Dict[str, Any]],
  187. bases: Tuple[type, ...] = ...,
  188. repr_ns: Optional[str] = ...,
  189. repr: bool = ...,
  190. cmp: bool = ...,
  191. hash: Optional[bool] = ...,
  192. init: bool = ...,
  193. slots: bool = ...,
  194. frozen: bool = ...,
  195. weakref_slot: bool = ...,
  196. str: bool = ...,
  197. auto_attribs: bool = ...,
  198. kw_only: bool = ...,
  199. cache_hash: bool = ...,
  200. ) -> type: ...
  201. # _funcs --
  202. # TODO: add support for returning TypedDict from the mypy plugin
  203. # FIXME: asdict/astuple do not honor their factory args. waiting on one of these:
  204. # https://github.com/python/mypy/issues/4236
  205. # https://github.com/python/typing/issues/253
  206. def asdict(
  207. inst: Any,
  208. recurse: bool = ...,
  209. filter: Optional[_FilterType] = ...,
  210. dict_factory: Type[Mapping[Any, Any]] = ...,
  211. retain_collection_types: bool = ...,
  212. ) -> Dict[str, Any]: ...
  213. # TODO: add support for returning NamedTuple from the mypy plugin
  214. def astuple(
  215. inst: Any,
  216. recurse: bool = ...,
  217. filter: Optional[_FilterType] = ...,
  218. tuple_factory: Type[Sequence] = ...,
  219. retain_collection_types: bool = ...,
  220. ) -> Tuple[Any, ...]: ...
  221. def has(cls: type) -> bool: ...
  222. def assoc(inst: _T, **changes: Any) -> _T: ...
  223. def evolve(inst: _T, **changes: Any) -> _T: ...
  224. # _config --
  225. def set_run_validators(run: bool) -> None: ...
  226. def get_run_validators() -> bool: ...
  227. # aliases --
  228. s = attributes = attrs
  229. ib = attr = attrib
  230. dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;)