2
2
from typing import Dict , Type
3
3
4
4
import pytest
5
- from attrs import NOTHING , Factory , define , field
5
+ from attrs import NOTHING , Factory , define , field , frozen
6
6
from hypothesis import assume , given
7
7
from hypothesis .strategies import data , just , one_of , sampled_from
8
8
@@ -450,12 +450,18 @@ class A:
450
450
def test_init_false_overridden (converter : BaseConverter ) -> None :
451
451
"""init=False handling can be overriden."""
452
452
453
+ @frozen
454
+ class Inner :
455
+ a : int
456
+
453
457
@define
454
458
class A :
455
459
a : int
456
460
b : int = field (init = False )
457
461
_c : int = field (init = False )
458
- d : int = field (init = False , default = 4 )
462
+ d : Inner = field (init = False )
463
+ e : int = field (init = False , default = 4 )
464
+ f : Inner = field (init = False , default = Inner (1 ))
459
465
460
466
converter .register_unstructure_hook (
461
467
A , make_dict_unstructure_fn (A , converter , _cattrs_include_init_false = True )
@@ -464,28 +470,36 @@ class A:
464
470
a = A (1 )
465
471
a .b = 2
466
472
a ._c = 3
473
+ a .d = Inner (4 )
467
474
468
- assert converter .unstructure (a ) == {"a" : 1 , "b" : 2 , "_c" : 3 , "d" : 4 }
475
+ assert converter .unstructure (a ) == {
476
+ "a" : 1 ,
477
+ "b" : 2 ,
478
+ "_c" : 3 ,
479
+ "d" : {"a" : 4 },
480
+ "e" : 4 ,
481
+ "f" : {"a" : 1 },
482
+ }
469
483
470
484
converter .register_structure_hook (
471
- A ,
472
- make_dict_structure_fn (
473
- A ,
474
- converter ,
475
- _cattrs_include_init_false = True ,
476
- _cattrs_detailed_validation = converter .detailed_validation ,
477
- ),
485
+ A , make_dict_structure_fn (A , converter , _cattrs_include_init_false = True )
478
486
)
479
487
480
- structured = converter .structure ({"a" : 1 , "b" : 2 , "_c" : 3 }, A )
488
+ structured = converter .structure ({"a" : 1 , "b" : 2 , "_c" : 3 , "d" : { "a" : 1 } }, A )
481
489
assert structured .b == 2
482
490
assert structured ._c == 3
483
- assert structured .d == 4
491
+ assert structured .d == Inner (1 )
492
+ assert structured .e == 4
493
+ assert structured .f == Inner (1 )
484
494
485
- structured = converter .structure ({"a" : 1 , "b" : 2 , "_c" : 3 , "d" : - 4 }, A )
495
+ structured = converter .structure (
496
+ {"a" : 1 , "b" : 2 , "_c" : 3 , "d" : {"a" : 5 }, "e" : - 4 , "f" : {"a" : 2 }}, A
497
+ )
486
498
assert structured .b == 2
487
499
assert structured ._c == 3
488
- assert structured .d == - 4
500
+ assert structured .d == Inner (5 )
501
+ assert structured .e == - 4
502
+ assert structured .f == Inner (2 )
489
503
490
504
491
505
def test_init_false_field_override (converter : BaseConverter ) -> None :
@@ -538,6 +552,29 @@ class A:
538
552
assert structured .d == - 4
539
553
540
554
555
+ def test_init_false_no_structure_hook (converter : BaseConverter ):
556
+ """init=False attributes with converters and `prefer_attrs_converters` work."""
557
+
558
+ @define
559
+ class A :
560
+ a : int = field (converter = int , init = False )
561
+
562
+ converter .register_structure_hook (
563
+ A ,
564
+ make_dict_structure_fn (
565
+ A ,
566
+ converter ,
567
+ _cattrs_prefer_attrib_converters = True ,
568
+ _cattrs_include_init_false = True ,
569
+ ),
570
+ )
571
+
572
+ res = A ()
573
+ res .a = 5
574
+
575
+ assert converter .structure ({"a" : "5" }, A ) == res
576
+
577
+
541
578
@given (forbid_extra_keys = ..., detailed_validation = ...)
542
579
def test_forbid_extra_keys_from_converter (
543
580
forbid_extra_keys : bool , detailed_validation : bool
0 commit comments