@@ -1195,9 +1195,7 @@ def test_custom_dataclass_names():
1195
1195
1196
1196
@pytest .mark .skipif (sys .version_info < (3 , 10 ), reason = 'slots are only supported for dataclasses in Python > 3.10' )
1197
1197
def test_slots () -> None :
1198
- kwargs = {'slots' : True }
1199
-
1200
- @dataclasses .dataclass (** kwargs )
1198
+ @dataclasses .dataclass (slots = True )
1201
1199
class Model :
1202
1200
x : int
1203
1201
@@ -1290,3 +1288,91 @@ def validate_b(cls, v: str, info: core_schema.FieldValidationInfo) -> str:
1290
1288
v = SchemaValidator (schema )
1291
1289
foo = v .validate_python ({'a' : 1 , 'b' : b'hello' })
1292
1290
assert dataclasses .asdict (foo ) == {'a' : 1 , 'b' : 'hello world!' }
1291
+
1292
+
1293
+ @dataclasses .dataclass (slots = True )
1294
+ class FooDataclassSlots :
1295
+ a : str
1296
+ b : bool
1297
+
1298
+
1299
+ @dataclasses .dataclass (slots = True )
1300
+ class FooDataclassSameSlots (FooDataclassSlots ):
1301
+ pass
1302
+
1303
+
1304
+ @dataclasses .dataclass (slots = True )
1305
+ class FooDataclassMoreSlots (FooDataclassSlots ):
1306
+ c : str
1307
+
1308
+
1309
+ @dataclasses .dataclass (slots = True )
1310
+ class DuplicateDifferentSlots :
1311
+ a : str
1312
+ b : bool
1313
+
1314
+
1315
+ @pytest .mark .parametrize (
1316
+ 'revalidate_instances,input_value,expected' ,
1317
+ [
1318
+ ('always' , {'a' : 'hello' , 'b' : True }, {'a' : 'hello' , 'b' : True }),
1319
+ ('always' , FooDataclassSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1320
+ ('always' , FooDataclassSameSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1321
+ ('always' , FooDataclassMoreSlots (a = 'hello' , b = True , c = 'more' ), Err (r'c\s+Unexpected keyword argument' )),
1322
+ (
1323
+ 'always' ,
1324
+ DuplicateDifferentSlots (a = 'hello' , b = True ),
1325
+ Err ('should be a dictionary or an instance of FooDataclass' ),
1326
+ ),
1327
+ # revalidate_instances='subclass-instances'
1328
+ ('subclass-instances' , {'a' : 'hello' , 'b' : True }, {'a' : 'hello' , 'b' : True }),
1329
+ ('subclass-instances' , FooDataclassSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1330
+ ('subclass-instances' , FooDataclassSlots (a = b'hello' , b = 'true' ), {'a' : b'hello' , 'b' : 'true' }),
1331
+ ('subclass-instances' , FooDataclassSameSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1332
+ ('subclass-instances' , FooDataclassSameSlots (a = b'hello' , b = 'true' ), {'a' : 'hello' , 'b' : True }),
1333
+ ('subclass-instances' , FooDataclassMoreSlots (a = 'hello' , b = True , c = 'more' ), Err ('Unexpected keyword argument' )),
1334
+ (
1335
+ 'subclass-instances' ,
1336
+ DuplicateDifferentSlots (a = 'hello' , b = True ),
1337
+ Err ('dictionary or an instance of FooDataclass' ),
1338
+ ),
1339
+ # revalidate_instances='never'
1340
+ ('never' , {'a' : 'hello' , 'b' : True }, {'a' : 'hello' , 'b' : True }),
1341
+ ('never' , FooDataclassSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1342
+ ('never' , FooDataclassSameSlots (a = 'hello' , b = True ), {'a' : 'hello' , 'b' : True }),
1343
+ ('never' , FooDataclassMoreSlots (a = 'hello' , b = True , c = 'more' ), {'a' : 'hello' , 'b' : True , 'c' : 'more' }),
1344
+ ('never' , FooDataclassMoreSlots (a = 'hello' , b = 'wrong' , c = 'more' ), {'a' : 'hello' , 'b' : 'wrong' , 'c' : 'more' }),
1345
+ (
1346
+ 'never' ,
1347
+ DuplicateDifferentSlots (a = 'hello' , b = True ),
1348
+ Err ('should be a dictionary or an instance of FooDataclass' ),
1349
+ ),
1350
+ ],
1351
+ )
1352
+ def test_slots_dataclass_subclass (revalidate_instances , input_value , expected ):
1353
+ schema = core_schema .dataclass_schema (
1354
+ FooDataclassSlots ,
1355
+ core_schema .dataclass_args_schema (
1356
+ 'FooDataclass' ,
1357
+ [
1358
+ core_schema .dataclass_field (name = 'a' , schema = core_schema .str_schema ()),
1359
+ core_schema .dataclass_field (name = 'b' , schema = core_schema .bool_schema ()),
1360
+ ],
1361
+ extra_behavior = 'forbid' ,
1362
+ ),
1363
+ revalidate_instances = revalidate_instances ,
1364
+ slots = True ,
1365
+ )
1366
+ v = SchemaValidator (schema )
1367
+
1368
+ if isinstance (expected , Err ):
1369
+ with pytest .raises (ValidationError , match = expected .message ) as exc_info :
1370
+ print (v .validate_python (input_value ))
1371
+
1372
+ # debug(exc_info.value.errors(include_url=False))
1373
+ if expected .errors is not None :
1374
+ assert exc_info .value .errors (include_url = False ) == expected .errors
1375
+ else :
1376
+ dc = v .validate_python (input_value )
1377
+ assert dataclasses .is_dataclass (dc )
1378
+ assert dataclasses .asdict (dc ) == expected
0 commit comments