@@ -1826,114 +1826,6 @@ class R:
1826
1826
self .assertEqual (new_sample .x , another_new_sample .x )
1827
1827
self .assertEqual (sample .y , another_new_sample .y )
1828
1828
1829
- def test_helper_make_dataclass (self ):
1830
- C = make_dataclass ('C' ,
1831
- [('x' , int ),
1832
- ('y' , int , field (default = 5 ))],
1833
- namespace = {'add_one' : lambda self : self .x + 1 })
1834
- c = C (10 )
1835
- self .assertEqual ((c .x , c .y ), (10 , 5 ))
1836
- self .assertEqual (c .add_one (), 11 )
1837
-
1838
-
1839
- def test_helper_make_dataclass_no_mutate_namespace (self ):
1840
- # Make sure a provided namespace isn't mutated.
1841
- ns = {}
1842
- C = make_dataclass ('C' ,
1843
- [('x' , int ),
1844
- ('y' , int , field (default = 5 ))],
1845
- namespace = ns )
1846
- self .assertEqual (ns , {})
1847
-
1848
- def test_helper_make_dataclass_base (self ):
1849
- class Base1 :
1850
- pass
1851
- class Base2 :
1852
- pass
1853
- C = make_dataclass ('C' ,
1854
- [('x' , int )],
1855
- bases = (Base1 , Base2 ))
1856
- c = C (2 )
1857
- self .assertIsInstance (c , C )
1858
- self .assertIsInstance (c , Base1 )
1859
- self .assertIsInstance (c , Base2 )
1860
-
1861
- def test_helper_make_dataclass_base_dataclass (self ):
1862
- @dataclass
1863
- class Base1 :
1864
- x : int
1865
- class Base2 :
1866
- pass
1867
- C = make_dataclass ('C' ,
1868
- [('y' , int )],
1869
- bases = (Base1 , Base2 ))
1870
- with self .assertRaisesRegex (TypeError , 'required positional' ):
1871
- c = C (2 )
1872
- c = C (1 , 2 )
1873
- self .assertIsInstance (c , C )
1874
- self .assertIsInstance (c , Base1 )
1875
- self .assertIsInstance (c , Base2 )
1876
-
1877
- self .assertEqual ((c .x , c .y ), (1 , 2 ))
1878
-
1879
- def test_helper_make_dataclass_init_var (self ):
1880
- def post_init (self , y ):
1881
- self .x *= y
1882
-
1883
- C = make_dataclass ('C' ,
1884
- [('x' , int ),
1885
- ('y' , InitVar [int ]),
1886
- ],
1887
- namespace = {'__post_init__' : post_init },
1888
- )
1889
- c = C (2 , 3 )
1890
- self .assertEqual (vars (c ), {'x' : 6 })
1891
- self .assertEqual (len (fields (c )), 1 )
1892
-
1893
- def test_helper_make_dataclass_class_var (self ):
1894
- C = make_dataclass ('C' ,
1895
- [('x' , int ),
1896
- ('y' , ClassVar [int ], 10 ),
1897
- ('z' , ClassVar [int ], field (default = 20 )),
1898
- ])
1899
- c = C (1 )
1900
- self .assertEqual (vars (c ), {'x' : 1 })
1901
- self .assertEqual (len (fields (c )), 1 )
1902
- self .assertEqual (C .y , 10 )
1903
- self .assertEqual (C .z , 20 )
1904
-
1905
- def test_helper_make_dataclass_other_params (self ):
1906
- C = make_dataclass ('C' ,
1907
- [('x' , int ),
1908
- ('y' , ClassVar [int ], 10 ),
1909
- ('z' , ClassVar [int ], field (default = 20 )),
1910
- ],
1911
- init = False )
1912
- # Make sure we have a repr, but no init.
1913
- self .assertNotIn ('__init__' , vars (C ))
1914
- self .assertIn ('__repr__' , vars (C ))
1915
-
1916
- # Make sure random other params don't work.
1917
- with self .assertRaisesRegex (TypeError , 'unexpected keyword argument' ):
1918
- C = make_dataclass ('C' ,
1919
- [],
1920
- xxinit = False )
1921
-
1922
- def test_helper_make_dataclass_no_types (self ):
1923
- C = make_dataclass ('Point' , ['x' , 'y' , 'z' ])
1924
- c = C (1 , 2 , 3 )
1925
- self .assertEqual (vars (c ), {'x' : 1 , 'y' : 2 , 'z' : 3 })
1926
- self .assertEqual (C .__annotations__ , {'x' : 'typing.Any' ,
1927
- 'y' : 'typing.Any' ,
1928
- 'z' : 'typing.Any' })
1929
-
1930
- C = make_dataclass ('Point' , ['x' , ('y' , int ), 'z' ])
1931
- c = C (1 , 2 , 3 )
1932
- self .assertEqual (vars (c ), {'x' : 1 , 'y' : 2 , 'z' : 3 })
1933
- self .assertEqual (C .__annotations__ , {'x' : 'typing.Any' ,
1934
- 'y' : int ,
1935
- 'z' : 'typing.Any' })
1936
-
1937
1829
1938
1830
class TestFieldNoAnnotation (unittest .TestCase ):
1939
1831
def test_field_without_annotation (self ):
@@ -2947,5 +2839,170 @@ def test_classvar_module_level_import(self):
2947
2839
self .assertNotIn ('not_iv4' , c .__dict__ )
2948
2840
2949
2841
2842
+ class TestMakeDataclass (unittest .TestCase ):
2843
+ def test_simple (self ):
2844
+ C = make_dataclass ('C' ,
2845
+ [('x' , int ),
2846
+ ('y' , int , field (default = 5 ))],
2847
+ namespace = {'add_one' : lambda self : self .x + 1 })
2848
+ c = C (10 )
2849
+ self .assertEqual ((c .x , c .y ), (10 , 5 ))
2850
+ self .assertEqual (c .add_one (), 11 )
2851
+
2852
+
2853
+ def test_no_mutate_namespace (self ):
2854
+ # Make sure a provided namespace isn't mutated.
2855
+ ns = {}
2856
+ C = make_dataclass ('C' ,
2857
+ [('x' , int ),
2858
+ ('y' , int , field (default = 5 ))],
2859
+ namespace = ns )
2860
+ self .assertEqual (ns , {})
2861
+
2862
+ def test_base (self ):
2863
+ class Base1 :
2864
+ pass
2865
+ class Base2 :
2866
+ pass
2867
+ C = make_dataclass ('C' ,
2868
+ [('x' , int )],
2869
+ bases = (Base1 , Base2 ))
2870
+ c = C (2 )
2871
+ self .assertIsInstance (c , C )
2872
+ self .assertIsInstance (c , Base1 )
2873
+ self .assertIsInstance (c , Base2 )
2874
+
2875
+ def test_base_dataclass (self ):
2876
+ @dataclass
2877
+ class Base1 :
2878
+ x : int
2879
+ class Base2 :
2880
+ pass
2881
+ C = make_dataclass ('C' ,
2882
+ [('y' , int )],
2883
+ bases = (Base1 , Base2 ))
2884
+ with self .assertRaisesRegex (TypeError , 'required positional' ):
2885
+ c = C (2 )
2886
+ c = C (1 , 2 )
2887
+ self .assertIsInstance (c , C )
2888
+ self .assertIsInstance (c , Base1 )
2889
+ self .assertIsInstance (c , Base2 )
2890
+
2891
+ self .assertEqual ((c .x , c .y ), (1 , 2 ))
2892
+
2893
+ def test_init_var (self ):
2894
+ def post_init (self , y ):
2895
+ self .x *= y
2896
+
2897
+ C = make_dataclass ('C' ,
2898
+ [('x' , int ),
2899
+ ('y' , InitVar [int ]),
2900
+ ],
2901
+ namespace = {'__post_init__' : post_init },
2902
+ )
2903
+ c = C (2 , 3 )
2904
+ self .assertEqual (vars (c ), {'x' : 6 })
2905
+ self .assertEqual (len (fields (c )), 1 )
2906
+
2907
+ def test_class_var (self ):
2908
+ C = make_dataclass ('C' ,
2909
+ [('x' , int ),
2910
+ ('y' , ClassVar [int ], 10 ),
2911
+ ('z' , ClassVar [int ], field (default = 20 )),
2912
+ ])
2913
+ c = C (1 )
2914
+ self .assertEqual (vars (c ), {'x' : 1 })
2915
+ self .assertEqual (len (fields (c )), 1 )
2916
+ self .assertEqual (C .y , 10 )
2917
+ self .assertEqual (C .z , 20 )
2918
+
2919
+ def test_other_params (self ):
2920
+ C = make_dataclass ('C' ,
2921
+ [('x' , int ),
2922
+ ('y' , ClassVar [int ], 10 ),
2923
+ ('z' , ClassVar [int ], field (default = 20 )),
2924
+ ],
2925
+ init = False )
2926
+ # Make sure we have a repr, but no init.
2927
+ self .assertNotIn ('__init__' , vars (C ))
2928
+ self .assertIn ('__repr__' , vars (C ))
2929
+
2930
+ # Make sure random other params don't work.
2931
+ with self .assertRaisesRegex (TypeError , 'unexpected keyword argument' ):
2932
+ C = make_dataclass ('C' ,
2933
+ [],
2934
+ xxinit = False )
2935
+
2936
+ def test_no_types (self ):
2937
+ C = make_dataclass ('Point' , ['x' , 'y' , 'z' ])
2938
+ c = C (1 , 2 , 3 )
2939
+ self .assertEqual (vars (c ), {'x' : 1 , 'y' : 2 , 'z' : 3 })
2940
+ self .assertEqual (C .__annotations__ , {'x' : 'typing.Any' ,
2941
+ 'y' : 'typing.Any' ,
2942
+ 'z' : 'typing.Any' })
2943
+
2944
+ C = make_dataclass ('Point' , ['x' , ('y' , int ), 'z' ])
2945
+ c = C (1 , 2 , 3 )
2946
+ self .assertEqual (vars (c ), {'x' : 1 , 'y' : 2 , 'z' : 3 })
2947
+ self .assertEqual (C .__annotations__ , {'x' : 'typing.Any' ,
2948
+ 'y' : int ,
2949
+ 'z' : 'typing.Any' })
2950
+
2951
+ def test_invalid_type_specification (self ):
2952
+ for bad_field in [(),
2953
+ (1 , 2 , 3 , 4 ),
2954
+ ]:
2955
+ with self .subTest (bad_field = bad_field ):
2956
+ with self .assertRaisesRegex (TypeError , r'Invalid field: ' ):
2957
+ make_dataclass ('C' , ['a' , bad_field ])
2958
+
2959
+ # And test for things with no len().
2960
+ for bad_field in [float ,
2961
+ lambda x :x ,
2962
+ ]:
2963
+ with self .subTest (bad_field = bad_field ):
2964
+ with self .assertRaisesRegex (TypeError , r'has no len\(\)' ):
2965
+ make_dataclass ('C' , ['a' , bad_field ])
2966
+
2967
+ def test_duplicate_field_names (self ):
2968
+ for field in ['a' , 'ab' ]:
2969
+ with self .subTest (field = field ):
2970
+ with self .assertRaisesRegex (TypeError , 'Field name duplicated' ):
2971
+ make_dataclass ('C' , [field , 'a' , field ])
2972
+
2973
+ def test_keyword_field_names (self ):
2974
+ for field in ['for' , 'async' , 'await' , 'as' ]:
2975
+ with self .subTest (field = field ):
2976
+ with self .assertRaisesRegex (TypeError , 'must not be keywords' ):
2977
+ make_dataclass ('C' , ['a' , field ])
2978
+ with self .assertRaisesRegex (TypeError , 'must not be keywords' ):
2979
+ make_dataclass ('C' , [field ])
2980
+ with self .assertRaisesRegex (TypeError , 'must not be keywords' ):
2981
+ make_dataclass ('C' , [field , 'a' ])
2982
+
2983
+ def test_non_identifier_field_names (self ):
2984
+ for field in ['()' , 'x,y' , '*' , '2@3' , '' , 'little johnny tables' ]:
2985
+ with self .subTest (field = field ):
2986
+ with self .assertRaisesRegex (TypeError , 'must be valid identifers' ):
2987
+ make_dataclass ('C' , ['a' , field ])
2988
+ with self .assertRaisesRegex (TypeError , 'must be valid identifers' ):
2989
+ make_dataclass ('C' , [field ])
2990
+ with self .assertRaisesRegex (TypeError , 'must be valid identifers' ):
2991
+ make_dataclass ('C' , [field , 'a' ])
2992
+
2993
+ def test_underscore_field_names (self ):
2994
+ # Unlike namedtuple, it's okay if dataclass field names have
2995
+ # an underscore.
2996
+ make_dataclass ('C' , ['_' , '_a' , 'a_a' , 'a_' ])
2997
+
2998
+ def test_funny_class_names_names (self ):
2999
+ # No reason to prevent weird class names, since
3000
+ # types.new_class allows them.
3001
+ for classname in ['()' , 'x,y' , '*' , '2@3' , '' ]:
3002
+ with self .subTest (classname = classname ):
3003
+ C = make_dataclass (classname , ['a' , 'b' ])
3004
+ self .assertEqual (C .__name__ , classname )
3005
+
3006
+
2950
3007
if __name__ == '__main__' :
2951
3008
unittest .main ()
0 commit comments