@@ -1712,91 +1712,6 @@ class Parent(Generic[T]):
1712
1712
# Check MRO resolution.
1713
1713
self .assertEqual (Child .__mro__ , (Child , Parent , Generic , object ))
1714
1714
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
-
1800
1715
def test_dataclassses_pickleable (self ):
1801
1716
global P , Q , R
1802
1717
@dataclass
@@ -3003,6 +2918,126 @@ def test_funny_class_names_names(self):
3003
2918
C = make_dataclass (classname , ['a' , 'b' ])
3004
2919
self .assertEqual (C .__name__ , classname )
3005
2920
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
+
3006
3041
3007
3042
if __name__ == '__main__' :
3008
3043
unittest .main ()
0 commit comments