Skip to content

Commit cf3d461

Browse files
committed
Raise a deprecation warning when evolve receives insta as a kw arg
Fixes #1109
1 parent 359c2db commit cf3d461

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

src/attr/_funcs.py

+23-5
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33

44
import copy
5+
import warnings
56

67
from ._compat import PY_3_9_PLUS, get_generic_base
78
from ._make import NOTHING, _obj_setattr, fields
@@ -331,8 +332,6 @@ def assoc(inst, **changes):
331332
This function will not be removed du to the slightly different approach
332333
compared to `attrs.evolve`.
333334
"""
334-
import warnings
335-
336335
warnings.warn(
337336
"assoc is deprecated and will be removed after 2018/01.",
338337
DeprecationWarning,
@@ -350,9 +349,10 @@ def assoc(inst, **changes):
350349
return new
351350

352351

353-
def evolve(inst, **changes):
352+
def evolve(*args, **changes):
354353
"""
355-
Create a new instance, based on *inst* with *changes* applied.
354+
Create a new instance, based on the first positional argument with
355+
*changes* applied.
356356
357357
:param inst: Instance of a class with *attrs* attributes.
358358
:param changes: Keyword changes in the new copy.
@@ -364,8 +364,26 @@ def evolve(inst, **changes):
364364
:raise attrs.exceptions.NotAnAttrsClassError: If *cls* is not an *attrs*
365365
class.
366366
367-
.. versionadded:: 17.1.0
367+
.. versionadded:: 17.1.0
368+
.. deprecated:: 23.1.0
369+
It is now deprecated to pass the instance using the keyword argument
370+
*inst*. It will raise a warning until at least April 2024, after which
371+
it will become an error. Always pass the instance as a positional
372+
argument.
368373
"""
374+
# Try to get instance by positional argument first.
375+
# Use changes otherwise and warn it'll break.
376+
if args:
377+
(inst,) = args
378+
else:
379+
warnings.warn(
380+
"Passing the instance per keyword argument is deprecated and "
381+
"will stop working in, or after, April 2024.",
382+
DeprecationWarning,
383+
stacklevel=2,
384+
)
385+
inst = changes.pop("inst")
386+
369387
cls = inst.__class__
370388
attrs = fields(cls)
371389
for a in attrs:

tests/test_funcs.py

+15
Original file line numberDiff line numberDiff line change
@@ -707,3 +707,18 @@ class Cls2:
707707
assert Cls1({"foo": 42, "param2": 42}) == attr.evolve(
708708
obj1a, param1=obj2b
709709
)
710+
711+
def test_inst_kw(self):
712+
"""
713+
If `inst` is passed per kw argument, a warning is raised.
714+
See #1109
715+
"""
716+
717+
@attr.s
718+
class C:
719+
pass
720+
721+
with pytest.warns(DeprecationWarning) as wi:
722+
evolve(inst=C())
723+
724+
assert __file__ == wi.list[0].filename

0 commit comments

Comments
 (0)