-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Support factory= in attr plugin. #5005
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -771,3 +771,32 @@ class FFrozen(F): | |
def bar(self) -> bool: | ||
return self._cb(5, 6) | ||
[builtins fixtures/callable.pyi] | ||
|
||
[case testAttrsWithFactory] | ||
from typing import List | ||
import attr | ||
def my_factory() -> int: | ||
return 7 | ||
@attr.s | ||
class A: | ||
x: List[int] = attr.ib(factory=list) | ||
y: int = attr.ib(factory=my_factory) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add also a test where this fails due to a wrong return type of the factory function. |
||
A() | ||
[builtins fixtures/list.pyi] | ||
|
||
[case testAttrsFactoryAndDefault] | ||
import attr | ||
@attr.s | ||
class A: | ||
x: int = attr.ib(factory=int, default=7) # E: Can't pass both `default` and `factory`. | ||
[builtins fixtures/bool.pyi] | ||
|
||
[case testAttrsFactoryBadReturn] | ||
import attr | ||
def my_factory() -> int: | ||
return 7 | ||
@attr.s | ||
class A: | ||
x: int = attr.ib(factory=list) # E: Incompatible types in assignment (expression has type "List[T]", variable has type "int") | ||
y: str = attr.ib(factory=my_factory) # E: Incompatible types in assignment (expression has type "int", variable has type "str") | ||
[builtins fixtures/list.pyi] |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,57 +1,97 @@ | ||
from typing import TypeVar, overload, Callable, Any, Type, Optional | ||
from typing import TypeVar, overload, Callable, Any, Type, Optional, Union, Sequence, Mapping | ||
|
||
_T = TypeVar('_T') | ||
_C = TypeVar('_C', bound=type) | ||
|
||
_ValidatorType = Callable[[Any, Any, _T], Any] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I thought validator should return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The return value of validators is ignored. A validation error is a raised exception. However I don't want to force a "None" |
||
_ConverterType = Callable[[Any], _T] | ||
_FilterType = Callable[[Any, Any], bool] | ||
_ValidatorArgType = Union[_ValidatorType[_T], Sequence[_ValidatorType[_T]]] | ||
|
||
# This form catches an explicit None or no default and infers the type from the other arguments. | ||
@overload | ||
def attrib(default: None = ..., | ||
validator: Optional[_ValidatorArgType[_T]] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: Optional[_ConverterType[_T]] = ..., | ||
metadata: Optional[Mapping[Any, Any]] = ..., | ||
type: Optional[Type[_T]] = ..., | ||
converter: Optional[_ConverterType[_T]] = ..., | ||
factory: Optional[Callable[[], _T]] = ..., | ||
) -> _T: ... | ||
# This form catches an explicit default argument. | ||
@overload | ||
def attr(default: Optional[_T] = ..., | ||
validator: Optional[Any] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: Optional[Callable[[Any], _T]] = ..., | ||
metadata: Any = ..., | ||
type: Optional[Type[_T]] = ..., | ||
converter: Optional[Callable[[Any], _T]] = ...) -> _T: ... | ||
def attrib(default: _T, | ||
validator: Optional[_ValidatorArgType[_T]] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: Optional[_ConverterType[_T]] = ..., | ||
metadata: Optional[Mapping[Any, Any]] = ..., | ||
type: Optional[Type[_T]] = ..., | ||
converter: Optional[_ConverterType[_T]] = ..., | ||
factory: Optional[Callable[[], _T]] = ..., | ||
) -> _T: ... | ||
# This form catches explicit None or no default but with no other arguments returns Any. | ||
@overload | ||
def attr(default: None = ..., | ||
validator: None = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: Optional[Callable[[Any], _T]] = ..., | ||
metadata: Any = ..., | ||
type: None = ..., | ||
converter: None = ...) -> Any: ... | ||
def attrib(default: None = ..., | ||
validator: None = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: None = ..., | ||
metadata: Optional[Mapping[Any, Any]] = ..., | ||
type: None = ..., | ||
converter: None = ..., | ||
factory: None = ..., | ||
) -> Any: ... | ||
# This form covers type=non-Type: e.g. forward references (str), Any | ||
@overload | ||
def attrib(default: Optional[_T] = ..., | ||
validator: Optional[_ValidatorArgType[_T]] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
convert: Optional[_ConverterType[_T]] = ..., | ||
metadata: Optional[Mapping[Any, Any]] = ..., | ||
type: object = ..., | ||
converter: Optional[_ConverterType[_T]] = ..., | ||
factory: Optional[Callable[[], _T]] = ..., | ||
) -> Any: ... | ||
|
||
@overload | ||
def attributes(maybe_cls: _C, | ||
these: Optional[Any] = ..., | ||
repr_ns: Optional[str] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
slots: bool = ..., | ||
frozen: bool = ..., | ||
str: bool = ..., | ||
auto_attribs: bool = ...) -> _C: ... | ||
def attrs(maybe_cls: _C, | ||
these: Optional[Mapping[str, Any]] = ..., | ||
repr_ns: Optional[str] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
slots: bool = ..., | ||
frozen: bool = ..., | ||
str: bool = ..., | ||
auto_attribs: bool = ...) -> _C: ... | ||
@overload | ||
def attributes(maybe_cls: None = ..., | ||
these: Optional[Any] = ..., | ||
repr_ns: Optional[str] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
slots: bool = ..., | ||
frozen: bool = ..., | ||
str: bool = ..., | ||
auto_attribs: bool = ...) -> Callable[[_C], _C]: ... | ||
def attrs(maybe_cls: None = ..., | ||
these: Optional[Mapping[str, Any]] = ..., | ||
repr_ns: Optional[str] = ..., | ||
repr: bool = ..., | ||
cmp: bool = ..., | ||
hash: Optional[bool] = ..., | ||
init: bool = ..., | ||
slots: bool = ..., | ||
frozen: bool = ..., | ||
str: bool = ..., | ||
auto_attribs: bool = ...) -> Callable[[_C], _C]: ... | ||
|
||
|
||
# aliases | ||
s = attrs = attributes | ||
ib = attrib = attr | ||
s = attributes = attrs | ||
ib = attr = attrib | ||
dataclass = attrs # Technically, partial(attrs, auto_attribs=True) ;) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is a good idea to always add tests for any newly added error messages.