Add attr.field (#669)

* Add attr.field

* Add newsfragment

* better wordzzz

* Typo and clarification
This commit is contained in:
Hynek Schlawack 2020-08-20 19:01:34 +02:00 committed by GitHub
parent c67a649b38
commit fda437c91f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 128 additions and 9 deletions

View File

@ -0,0 +1,5 @@
We have also provisionally added ``attr.field()`` that supplants ``attr.ib()``.
It also requires at least Python 3.6 and is keyword-only.
Other than that, it only dropped a few arguments, but changed no defaults.
As with ``attr.s()``: ``attr.ib()`` is not going anywhere.

View File

@ -622,10 +622,16 @@ Therefore your constructive feedback in the linked issues above is strongly enco
Alias for `attr.define`.
.. versionadded:: 20.1.0
.. function:: attr.frozen(same_as_define)
Behaves the same as `attr.define` but sets *frozen=True* and *on_setattr=None*.
.. versionadded:: 20.1.0
.. autofunction:: attr.field
Deprecated APIs
---------------

View File

@ -71,6 +71,6 @@ __all__ = [
]
if sys.version_info[:2] >= (3, 6):
from ._next_gen import define, frozen, mutable
from ._next_gen import define, field, frozen, mutable
__all__.extend((define, frozen, mutable))
__all__.extend((define, field, frozen, mutable))

View File

@ -182,6 +182,77 @@ def attrib(
on_setattr: Optional[_OnSetAttrArgType] = ...,
) -> Any: ...
@overload
def field(
*,
default: None = ...,
validator: None = ...,
repr: _ReprArgType = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
converter: None = ...,
factory: None = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
) -> Any: ...
# This form catches an explicit None or no default and infers the type from the
# other arguments.
@overload
def field(
*,
default: None = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
converter: Optional[_ConverterType] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
) -> _T: ...
# This form catches an explicit default argument.
@overload
def field(
*,
default: _T,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
converter: Optional[_ConverterType] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
) -> _T: ...
# This form covers type=non-Type: e.g. forward references (str), Any
@overload
def field(
*,
default: Optional[_T] = ...,
validator: Optional[_ValidatorArgType[_T]] = ...,
repr: _ReprArgType = ...,
hash: Optional[bool] = ...,
init: bool = ...,
metadata: Optional[Mapping[Any, Any]] = ...,
converter: Optional[_ConverterType] = ...,
factory: Optional[Callable[[], _T]] = ...,
kw_only: bool = ...,
eq: Optional[bool] = ...,
order: Optional[bool] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
) -> Any: ...
@overload
def attrs(
maybe_cls: _C,
these: Optional[Dict[str, Any]] = ...,

View File

@ -10,7 +10,7 @@ from functools import partial
from attr.exceptions import UnannotatedAttributeError
from . import setters
from ._make import attrs
from ._make import NOTHING, attrib, attrs
def define(
@ -32,7 +32,7 @@ def define(
order=False,
auto_detect=True,
getstate_setstate=None,
on_setattr=setters.validate
on_setattr=setters.validate,
):
r"""
The only behavioral difference is the handling of the *auto_attribs*
@ -84,3 +84,40 @@ def define(
mutable = define
frozen = partial(define, frozen=True, on_setattr=None)
def field(
*,
default=NOTHING,
validator=None,
repr=True,
hash=None,
init=True,
metadata=None,
converter=None,
factory=None,
kw_only=False,
eq=None,
order=None,
on_setattr=None,
):
"""
Identical to `attr.ib`, except keyword-only and with some arguments
removed.
.. versionadded:: 20.1.0
"""
return attrib(
default=default,
validator=validator,
repr=repr,
hash=hash,
init=init,
metadata=metadata,
converter=converter,
factory=factory,
kw_only=kw_only,
eq=eq,
order=order,
on_setattr=on_setattr,
)

View File

@ -40,7 +40,7 @@ class TestNextGen:
@attr.define
class Validated:
x: int = attr.ib(validator=attr.validators.instance_of(int))
x: int = attr.field(validator=attr.validators.instance_of(int))
v = Validated(1)
@ -67,13 +67,13 @@ class TestNextGen:
"""
Don't guess if auto_attrib is set explicitly.
Having an unannotated attr.ib fails.
Having an unannotated attr.ib/attr.field fails.
"""
with pytest.raises(attr.exceptions.UnannotatedAttributeError):
@attr.define(auto_attribs=True)
class ThisFails:
x = attr.ib()
x = attr.field()
y: int
def test_override_auto_attribs_false(self):
@ -97,7 +97,7 @@ class TestNextGen:
@attr.define
class OldSchool:
x = attr.ib()
x = attr.field()
assert OldSchool(1) == OldSchool(1)

View File

@ -211,7 +211,7 @@ class ValidatedSetter:
# Provisional APIs
@attr.define(order=True)
class NGClass:
x: int
x: int = attr.field(default=42)
# XXX: needs support in mypy