From 34adf17ef186c4010567406645f3ad2025774719 Mon Sep 17 00:00:00 2001 From: chrysle Date: Sat, 25 Feb 2023 10:31:41 +0100 Subject: [PATCH 1/6] Added `type` parameter to `attrs.field` and test --- src/attr/__init__.pyi | 4 ++++ src/attr/_next_gen.py | 5 ++++- tests/test_next_gen.py | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/src/attr/__init__.pyi b/src/attr/__init__.pyi index 1e70b593e..e7ee0cbd2 100644 --- a/src/attr/__init__.pyi +++ b/src/attr/__init__.pyi @@ -258,6 +258,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 @@ -278,6 +279,7 @@ def field( order: Optional[_EqOrderType] = ..., on_setattr: Optional[_OnSetAttrArgType] = ..., alias: Optional[str] = ..., + type: Optional[type] = ..., ) -> _T: ... # This form catches an explicit default argument. @@ -297,6 +299,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 @@ -316,6 +319,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)) diff --git a/src/attr/_next_gen.py b/src/attr/_next_gen.py index 1ce7b3d7e..c335ede6e 100644 --- a/src/attr/_next_gen.py +++ b/src/attr/_next_gen.py @@ -167,6 +167,7 @@ def field( hash=None, init=True, metadata=None, + type=None, converter=None, factory=None, kw_only=False, @@ -178,7 +179,8 @@ def field( """ Identical to `attr.ib`, except keyword-only and with some arguments removed. - + + .. versionadded:: 22.3.0 type parameter .. versionadded:: 20.1.0 """ return attrib( @@ -188,6 +190,7 @@ def field( hash=hash, init=init, metadata=metadata, + type=type, converter=converter, factory=factory, kw_only=kw_only, diff --git a/tests/test_next_gen.py b/tests/test_next_gen.py index cb6ee2a78..2989b1bfe 100644 --- a/tests/test_next_gen.py +++ b/tests/test_next_gen.py @@ -28,6 +28,14 @@ def test_simple(self): """ 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. From 6ec34d7f4f9f687ac045284d660f2b55b04866c7 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 28 Feb 2023 10:23:46 +0100 Subject: [PATCH 2/6] Added notice in examples.md --- docs/examples.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/examples.md b/docs/examples.md index 465dc3952..566db257c 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -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"]) >>> fields(C1) == fields(C2) True +>>> fields(C1).x.type + ``` 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`: From 0b74644ae3f41b4fe8143919979d7b6a731437ab Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Feb 2023 09:41:14 +0000 Subject: [PATCH 3/6] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- src/attr/_next_gen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/attr/_next_gen.py b/src/attr/_next_gen.py index c335ede6e..12b39a9c3 100644 --- a/src/attr/_next_gen.py +++ b/src/attr/_next_gen.py @@ -179,7 +179,7 @@ def field( """ Identical to `attr.ib`, except keyword-only and with some arguments removed. - + .. versionadded:: 22.3.0 type parameter .. versionadded:: 20.1.0 """ From ae23e32a4adb9094fd354360e9279fef7f4ba1d9 Mon Sep 17 00:00:00 2001 From: chrysle Date: Tue, 28 Feb 2023 10:46:47 +0100 Subject: [PATCH 4/6] Added changelog entry --- changelog.d/1107.change.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/1107.change.md diff --git a/changelog.d/1107.change.md b/changelog.d/1107.change.md new file mode 100644 index 000000000..30cb3be09 --- /dev/null +++ b/changelog.d/1107.change.md @@ -0,0 +1 @@ +Added `type` parameter to `attrs.field()` function. From 023da9a6bdac27750b2c27f98327926b0580e3bd Mon Sep 17 00:00:00 2001 From: chrysle Date: Sat, 18 Mar 2023 13:13:18 +0100 Subject: [PATCH 5/6] Fixed docs --- docs/examples.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/examples.md b/docs/examples.md index 566db257c..6329efc35 100644 --- a/docs/examples.md +++ b/docs/examples.md @@ -628,7 +628,7 @@ Sometimes you may want to create a class programmatically. ... class C1: ... 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 From 71577020502662b9b368903a94bf601aa8e2a22f Mon Sep 17 00:00:00 2001 From: Hynek Schlawack Date: Mon, 3 Apr 2023 16:36:43 +0200 Subject: [PATCH 6/6] Apply suggestions from code review --- changelog.d/1107.change.md | 4 +++- src/attr/_next_gen.py | 5 ++++- tests/test_next_gen.py | 2 ++ 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/changelog.d/1107.change.md b/changelog.d/1107.change.md index 30cb3be09..760649432 100644 --- a/changelog.d/1107.change.md +++ b/changelog.d/1107.change.md @@ -1 +1,3 @@ -Added `type` parameter to `attrs.field()` function. +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_. diff --git a/src/attr/_next_gen.py b/src/attr/_next_gen.py index 12b39a9c3..7c4d5db0c 100644 --- a/src/attr/_next_gen.py +++ b/src/attr/_next_gen.py @@ -180,7 +180,10 @@ def field( Identical to `attr.ib`, except keyword-only and with some arguments removed. - .. versionadded:: 22.3.0 type parameter + .. 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( diff --git a/tests/test_next_gen.py b/tests/test_next_gen.py index 2989b1bfe..7908a418c 100644 --- a/tests/test_next_gen.py +++ b/tests/test_next_gen.py @@ -33,7 +33,9 @@ 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):