Added `type` parameter to `attrs.field()` function (#1107)

* Added `type` parameter to `attrs.field` and test

* Added notice in examples.md

* [pre-commit.ci] auto fixes from pre-commit.com hooks

for more information, see https://pre-commit.ci

* Added changelog entry

* Fixed docs

* Apply suggestions from code review

---------

Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Hynek Schlawack <hs@ox.cx>
This commit is contained in:
chrysle 2023-04-03 16:40:45 +02:00 committed by GitHub
parent 359c2db460
commit 65ee286d6a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 28 additions and 3 deletions

View File

@ -0,0 +1,3 @@
Added *type* parameter to `attrs.field()` function for use with `attrs.make_class().
Please note that type checkers ignore type metadata passed into `make_class()`, but it can be useful if you're wrapping _attrs_.

View File

@ -471,7 +471,7 @@ If you're the author of a third-party library with *attrs* integration, please s
## Types
*attrs* also allows you to associate a type with an attribute using either the *type* argument to {func}`attr.ib` or using {pep}`526`-annotations:
*attrs* also allows you to associate a type with an attribute using either the *type* argument to {func}`attr.ib` and {func}`attr.field` or using {pep}`526`-annotations:
```{doctest}
>>> @define
@ -626,11 +626,13 @@ Sometimes you may want to create a class programmatically.
>>> from attrs import make_class
>>> @define
... class C1:
... x = field()
... x = field(type=int)
... y = field()
>>> C2 = make_class("C2", ["x", "y"])
>>> C2 = make_class("C2", {"x": field(type=int), "y": field()})
>>> fields(C1) == fields(C2)
True
>>> fields(C1).x.type
<class 'int'>
```
You can still have power over the attributes if you pass a dictionary of name: {func}`~attrs.field` mappings and can pass arguments to `@attr.s`:

View File

@ -259,6 +259,7 @@ def field(
order: Optional[bool] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
alias: Optional[str] = ...,
type: Optional[type] = ...,
) -> Any: ...
# This form catches an explicit None or no default and infers the type from the
@ -279,6 +280,7 @@ def field(
order: Optional[_EqOrderType] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
alias: Optional[str] = ...,
type: Optional[type] = ...,
) -> _T: ...
# This form catches an explicit default argument.
@ -298,6 +300,7 @@ def field(
order: Optional[_EqOrderType] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
alias: Optional[str] = ...,
type: Optional[type] = ...,
) -> _T: ...
# This form covers type=non-Type: e.g. forward references (str), Any
@ -317,6 +320,7 @@ def field(
order: Optional[_EqOrderType] = ...,
on_setattr: Optional[_OnSetAttrArgType] = ...,
alias: Optional[str] = ...,
type: Optional[type] = ...,
) -> Any: ...
@overload
@__dataclass_transform__(order_default=True, field_descriptors=(attrib, field))

View File

@ -167,6 +167,7 @@ def field(
hash=None,
init=True,
metadata=None,
type=None,
converter=None,
factory=None,
kw_only=False,
@ -179,6 +180,10 @@ def field(
Identical to `attr.ib`, except keyword-only and with some arguments
removed.
.. versionadded:: 22.3.0
The *type* parameter has been re-added; mostly for
{func}`attrs.make_class`. Please note that type checkers ignore this
metadata.
.. versionadded:: 20.1.0
"""
return attrib(
@ -188,6 +193,7 @@ def field(
hash=hash,
init=init,
metadata=metadata,
type=type,
converter=converter,
factory=factory,
kw_only=kw_only,

View File

@ -28,6 +28,16 @@ class TestNextGen:
"""
C("1", 2)
def test_field_type(self):
"""
Make class with attrs.field and type parameter.
"""
classFields = {"testint": attrs.field(type=int)}
A = attrs.make_class("A", classFields)
assert int == attrs.fields(A).testint.type
def test_no_slots(self):
"""
slots can be deactivated.