@@ -1592,3 +1592,124 @@ def _wrap_validator(cls, v, validator, info):
1592
1592
gc .collect ()
1593
1593
1594
1594
assert ref () is None
1595
+
1596
+
1597
+ init_test_cases = [
1598
+ ({'a' : 'hello' , 'b' : 'bye' }, 'ignore' , {'a' : 'hello' , 'b' : 'HELLO' }),
1599
+ ({'a' : 'hello' }, 'ignore' , {'a' : 'hello' , 'b' : 'HELLO' }),
1600
+ # note, for the case below, we don't actually support this case in Pydantic
1601
+ # it's disallowed in Pydantic to have a model with extra='allow' and a field
1602
+ # with init=False, so this case isn't really possible at the momment
1603
+ # however, no conflict arises here because we don't pass in the value for b
1604
+ # to __init__
1605
+ ({'a' : 'hello' }, 'allow' , {'a' : 'hello' , 'b' : 'HELLO' }),
1606
+ (
1607
+ {'a' : 'hello' , 'b' : 'bye' },
1608
+ 'forbid' ,
1609
+ Err (
1610
+ 'Unexpected keyword argument' ,
1611
+ errors = [
1612
+ {
1613
+ 'type' : 'unexpected_keyword_argument' ,
1614
+ 'loc' : ('b' ,),
1615
+ 'msg' : 'Unexpected keyword argument' ,
1616
+ 'input' : 'bye' ,
1617
+ }
1618
+ ],
1619
+ ),
1620
+ ),
1621
+ ({'a' : 'hello' }, 'forbid' , {'a' : 'hello' , 'b' : 'HELLO' }),
1622
+ ]
1623
+
1624
+
1625
+ @pytest .mark .parametrize (
1626
+ 'input_value,extra_behavior,expected' ,
1627
+ [
1628
+ * init_test_cases ,
1629
+ # special case - when init=False, extra='allow', and the value is provided
1630
+ # currently, it's disallowed in Pydantic to have a model with extra='allow'
1631
+ # and a field with init=False, so this case isn't really possible at the momment
1632
+ # TODO: open to changing this behavior, and changes won't be significantly breaking
1633
+ # because we currently don't support this case
1634
+ ({'a' : 'hello' , 'b' : 'bye' }, 'allow' , {'a' : 'hello' , 'b' : 'HELLO' }),
1635
+ ],
1636
+ )
1637
+ def test_dataclass_args_init (input_value , extra_behavior , expected ):
1638
+ @dataclasses .dataclass
1639
+ class Foo :
1640
+ a : str
1641
+ b : str
1642
+
1643
+ def __post_init__ (self ):
1644
+ self .b = self .a .upper ()
1645
+
1646
+ schema = core_schema .dataclass_schema (
1647
+ Foo ,
1648
+ core_schema .dataclass_args_schema (
1649
+ 'Foo' ,
1650
+ [
1651
+ core_schema .dataclass_field (name = 'a' , schema = core_schema .str_schema ()),
1652
+ core_schema .dataclass_field (name = 'b' , schema = core_schema .str_schema (), init = False ),
1653
+ ],
1654
+ extra_behavior = extra_behavior ,
1655
+ ),
1656
+ ['a' , 'b' ],
1657
+ post_init = True ,
1658
+ )
1659
+
1660
+ v = SchemaValidator (schema )
1661
+
1662
+ if isinstance (expected , Err ):
1663
+ with pytest .raises (ValidationError , match = re .escape (expected .message )) as exc_info :
1664
+ v .validate_python (input_value )
1665
+
1666
+ if expected .errors is not None :
1667
+ assert exc_info .value .errors (include_url = False ) == expected .errors
1668
+ else :
1669
+ assert dataclasses .asdict (v .validate_python (input_value )) == expected
1670
+
1671
+
1672
+ @pytest .mark .parametrize (
1673
+ 'input_value,extra_behavior,expected' ,
1674
+ [
1675
+ * init_test_cases ,
1676
+ # special case - allow override of default, even when init=False, if extra='allow'
1677
+ # TODO: we haven't really decided if this should be allowed or not
1678
+ # currently, it's disallowed in Pydantic to have a model with extra='allow'
1679
+ # and a field with init=False, so this case isn't really possible at the momment
1680
+ ({'a' : 'hello' , 'b' : 'bye' }, 'allow' , {'a' : 'hello' , 'b' : 'bye' }),
1681
+ ],
1682
+ )
1683
+ def test_dataclass_args_init_with_default (input_value , extra_behavior , expected ):
1684
+ @dataclasses .dataclass
1685
+ class Foo :
1686
+ a : str
1687
+ b : str
1688
+
1689
+ schema = core_schema .dataclass_schema (
1690
+ Foo ,
1691
+ core_schema .dataclass_args_schema (
1692
+ 'Foo' ,
1693
+ [
1694
+ core_schema .dataclass_field (name = 'a' , schema = core_schema .str_schema ()),
1695
+ core_schema .dataclass_field (
1696
+ name = 'b' ,
1697
+ schema = core_schema .with_default_schema (schema = core_schema .str_schema (), default = 'HELLO' ),
1698
+ init = False ,
1699
+ ),
1700
+ ],
1701
+ extra_behavior = extra_behavior ,
1702
+ ),
1703
+ ['a' , 'b' ],
1704
+ )
1705
+
1706
+ v = SchemaValidator (schema )
1707
+
1708
+ if isinstance (expected , Err ):
1709
+ with pytest .raises (ValidationError , match = re .escape (expected .message )) as exc_info :
1710
+ v .validate_python (input_value )
1711
+
1712
+ if expected .errors is not None :
1713
+ assert exc_info .value .errors (include_url = False ) == expected .errors
1714
+ else :
1715
+ assert dataclasses .asdict (v .validate_python (input_value )) == expected
0 commit comments