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