@@ -1712,91 +1712,6 @@ class Parent(Generic[T]):
17121712 # Check MRO resolution.
17131713 self .assertEqual (Child .__mro__ , (Child , Parent , Generic , object ))
17141714
1715- def test_helper_replace (self ):
1716- @dataclass (frozen = True )
1717- class C :
1718- x : int
1719- y : int
1720-
1721- c = C (1 , 2 )
1722- c1 = replace (c , x = 3 )
1723- self .assertEqual (c1 .x , 3 )
1724- self .assertEqual (c1 .y , 2 )
1725-
1726- def test_helper_replace_frozen (self ):
1727- @dataclass (frozen = True )
1728- class C :
1729- x : int
1730- y : int
1731- z : int = field (init = False , default = 10 )
1732- t : int = field (init = False , default = 100 )
1733-
1734- c = C (1 , 2 )
1735- c1 = replace (c , x = 3 )
1736- self .assertEqual ((c .x , c .y , c .z , c .t ), (1 , 2 , 10 , 100 ))
1737- self .assertEqual ((c1 .x , c1 .y , c1 .z , c1 .t ), (3 , 2 , 10 , 100 ))
1738-
1739-
1740- with self .assertRaisesRegex (ValueError , 'init=False' ):
1741- replace (c , x = 3 , z = 20 , t = 50 )
1742- with self .assertRaisesRegex (ValueError , 'init=False' ):
1743- replace (c , z = 20 )
1744- replace (c , x = 3 , z = 20 , t = 50 )
1745-
1746- # Make sure the result is still frozen.
1747- with self .assertRaisesRegex (FrozenInstanceError , "cannot assign to field 'x'" ):
1748- c1 .x = 3
1749-
1750- # Make sure we can't replace an attribute that doesn't exist,
1751- # if we're also replacing one that does exist. Test this
1752- # here, because setting attributes on frozen instances is
1753- # handled slightly differently from non-frozen ones.
1754- with self .assertRaisesRegex (TypeError , r"__init__\(\) got an unexpected "
1755- "keyword argument 'a'" ):
1756- c1 = replace (c , x = 20 , a = 5 )
1757-
1758- def test_helper_replace_invalid_field_name (self ):
1759- @dataclass (frozen = True )
1760- class C :
1761- x : int
1762- y : int
1763-
1764- c = C (1 , 2 )
1765- with self .assertRaisesRegex (TypeError , r"__init__\(\) got an unexpected "
1766- "keyword argument 'z'" ):
1767- c1 = replace (c , z = 3 )
1768-
1769- def test_helper_replace_invalid_object (self ):
1770- @dataclass (frozen = True )
1771- class C :
1772- x : int
1773- y : int
1774-
1775- with self .assertRaisesRegex (TypeError , 'dataclass instance' ):
1776- replace (C , x = 3 )
1777-
1778- with self .assertRaisesRegex (TypeError , 'dataclass instance' ):
1779- replace (0 , x = 3 )
1780-
1781- def test_helper_replace_no_init (self ):
1782- @dataclass
1783- class C :
1784- x : int
1785- y : int = field (init = False , default = 10 )
1786-
1787- c = C (1 )
1788- c .y = 20
1789-
1790- # Make sure y gets the default value.
1791- c1 = replace (c , x = 5 )
1792- self .assertEqual ((c1 .x , c1 .y ), (5 , 10 ))
1793-
1794- # Trying to replace y is an error.
1795- with self .assertRaisesRegex (ValueError , 'init=False' ):
1796- replace (c , x = 2 , y = 30 )
1797- with self .assertRaisesRegex (ValueError , 'init=False' ):
1798- replace (c , y = 30 )
1799-
18001715 def test_dataclassses_pickleable (self ):
18011716 global P , Q , R
18021717 @dataclass
@@ -3003,6 +2918,126 @@ def test_funny_class_names_names(self):
30032918 C = make_dataclass (classname , ['a' , 'b' ])
30042919 self .assertEqual (C .__name__ , classname )
30052920
2921+ class TestReplace (unittest .TestCase ):
2922+ def test (self ):
2923+ @dataclass (frozen = True )
2924+ class C :
2925+ x : int
2926+ y : int
2927+
2928+ c = C (1 , 2 )
2929+ c1 = replace (c , x = 3 )
2930+ self .assertEqual (c1 .x , 3 )
2931+ self .assertEqual (c1 .y , 2 )
2932+
2933+ def test_frozen (self ):
2934+ @dataclass (frozen = True )
2935+ class C :
2936+ x : int
2937+ y : int
2938+ z : int = field (init = False , default = 10 )
2939+ t : int = field (init = False , default = 100 )
2940+
2941+ c = C (1 , 2 )
2942+ c1 = replace (c , x = 3 )
2943+ self .assertEqual ((c .x , c .y , c .z , c .t ), (1 , 2 , 10 , 100 ))
2944+ self .assertEqual ((c1 .x , c1 .y , c1 .z , c1 .t ), (3 , 2 , 10 , 100 ))
2945+
2946+
2947+ with self .assertRaisesRegex (ValueError , 'init=False' ):
2948+ replace (c , x = 3 , z = 20 , t = 50 )
2949+ with self .assertRaisesRegex (ValueError , 'init=False' ):
2950+ replace (c , z = 20 )
2951+ replace (c , x = 3 , z = 20 , t = 50 )
2952+
2953+ # Make sure the result is still frozen.
2954+ with self .assertRaisesRegex (FrozenInstanceError , "cannot assign to field 'x'" ):
2955+ c1 .x = 3
2956+
2957+ # Make sure we can't replace an attribute that doesn't exist,
2958+ # if we're also replacing one that does exist. Test this
2959+ # here, because setting attributes on frozen instances is
2960+ # handled slightly differently from non-frozen ones.
2961+ with self .assertRaisesRegex (TypeError , r"__init__\(\) got an unexpected "
2962+ "keyword argument 'a'" ):
2963+ c1 = replace (c , x = 20 , a = 5 )
2964+
2965+ def test_invalid_field_name (self ):
2966+ @dataclass (frozen = True )
2967+ class C :
2968+ x : int
2969+ y : int
2970+
2971+ c = C (1 , 2 )
2972+ with self .assertRaisesRegex (TypeError , r"__init__\(\) got an unexpected "
2973+ "keyword argument 'z'" ):
2974+ c1 = replace (c , z = 3 )
2975+
2976+ def test_invalid_object (self ):
2977+ @dataclass (frozen = True )
2978+ class C :
2979+ x : int
2980+ y : int
2981+
2982+ with self .assertRaisesRegex (TypeError , 'dataclass instance' ):
2983+ replace (C , x = 3 )
2984+
2985+ with self .assertRaisesRegex (TypeError , 'dataclass instance' ):
2986+ replace (0 , x = 3 )
2987+
2988+ def test_no_init (self ):
2989+ @dataclass
2990+ class C :
2991+ x : int
2992+ y : int = field (init = False , default = 10 )
2993+
2994+ c = C (1 )
2995+ c .y = 20
2996+
2997+ # Make sure y gets the default value.
2998+ c1 = replace (c , x = 5 )
2999+ self .assertEqual ((c1 .x , c1 .y ), (5 , 10 ))
3000+
3001+ # Trying to replace y is an error.
3002+ with self .assertRaisesRegex (ValueError , 'init=False' ):
3003+ replace (c , x = 2 , y = 30 )
3004+
3005+ with self .assertRaisesRegex (ValueError , 'init=False' ):
3006+ replace (c , y = 30 )
3007+
3008+ def test_classvar (self ):
3009+ @dataclass
3010+ class C :
3011+ x : int
3012+ y : ClassVar [int ] = 1000
3013+
3014+ c = C (1 )
3015+ d = C (2 )
3016+
3017+ self .assertIs (c .y , d .y )
3018+ self .assertEqual (c .y , 1000 )
3019+
3020+ # Trying to replace y is an error: can't replace ClassVars.
3021+ with self .assertRaisesRegex (TypeError , r"__init__\(\) got an "
3022+ "unexpected keyword argument 'y'" ):
3023+ replace (c , y = 30 )
3024+
3025+ replace (c , x = 5 )
3026+
3027+ ## def test_initvar(self):
3028+ ## @dataclass
3029+ ## class C:
3030+ ## x: int
3031+ ## y: InitVar[int]
3032+
3033+ ## c = C(1, 10)
3034+ ## d = C(2, 20)
3035+
3036+ ## # In our case, replacing an InitVar is a no-op
3037+ ## self.assertEqual(c, replace(c, y=5))
3038+
3039+ ## replace(c, x=5)
3040+
30063041
30073042if __name__ == '__main__' :
30083043 unittest .main ()
0 commit comments