Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion schema/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -350,7 +350,15 @@ def _priority(s: Any) -> int:


def _invoke_with_optional_kwargs(f: Callable[..., Any], **kwargs: Any) -> Any:
s = inspect.signature(f)
try:
s = inspect.signature(f)
except (ValueError, TypeError):
# Some callables -- notably C-implemented built-ins such as ``dict``
# or ``int`` -- do not expose an introspectable signature. We cannot
# tell whether they accept keyword arguments, so fall back to calling
# them without any, matching how such defaults behaved before
# validate() keyword arguments were forwarded to them.
return f()
if len(s.parameters) == 0:
return f()
return f(**kwargs)
Expand Down
13 changes: 13 additions & 0 deletions test_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,19 @@ def convert(data, increment):
assert d["k"] == 1 and d["d"]["k"] == 42 and d["d"]["l"][0]["l"] == [3, 4, 5]


def test_optional_callable_default_builtin_c_callables():
# ``inspect.signature`` raises for some C-implemented built-ins (e.g.
# ``dict`` and ``int``), which previously made them unusable as
# ``Optional`` defaults. See https://github.com/keleshev/schema/issues/272
assert Schema({Optional("k", default=dict): dict}).validate({}) == {"k": {}}
assert Schema({Optional("k", default=int): int}).validate({}) == {"k": 0}
assert Schema({Optional("k", default=list): list}).validate({}) == {"k": []}
# validate() keyword arguments are still forwarded to callables that
# expose an introspectable signature accepting them.
s = Schema({Optional("k", default=lambda **kw: kw["increment"]): int})
assert s.validate({}, increment=5) == {"k": 5}


def test_inheritance_optional():
def convert(data, increment):
if isinstance(data, int):
Expand Down