@@ -1592,3 +1592,124 @@ def _wrap_validator(cls, v, validator, info):
15921592 gc .collect ()
15931593
15941594 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