D4Vinci/Scrapling · error · TypeError
Callable filter function must have at least one argument to
Error message
Callable filter function must have at least one argument to take `Selector` objects.
What it means
A callable passed to find_all() takes zero parameters, so it cannot receive the Selector objects it is supposed to filter. scrapling inspects the callable's signature with inspect.signature and requires at least one positional parameter.
Source
Thrown at scrapling/parser.py:743
if not all(map(lambda x: isinstance(x, str), arg)):
raise TypeError("Nested Iterables are not accepted, only iterables of tag names are accepted")
tags.update(set(arg))
elif isinstance(arg, dict):
if not all([(isinstance(k, str) and isinstance(v, str)) for k, v in arg.items()]):
raise TypeError(
"Nested dictionaries are not accepted, only string keys and string values are accepted"
)
attributes.update(arg)
elif isinstance(arg, re_Pattern):
patterns.add(arg)
elif callable(arg):
if len(signature(arg).parameters) > 0:
functions.append(arg)
else:
raise TypeError(
"Callable filter function must have at least one argument to take `Selector` objects."
)
else:
raise TypeError(f'Argument with type "{type(arg)}" is not accepted, please read the docs.')
if not all([(isinstance(k, str) and isinstance(v, str)) for k, v in kwargs.items()]):
raise TypeError("Only string values are accepted for arguments")
for attribute_name, value in kwargs.items():
# Only replace names for kwargs, replacing them in dictionaries doesn't make sense
attribute_name = _whitelisted.get(attribute_name, attribute_name)
attributes[attribute_name] = value
# It's easier and faster to build a selector than traversing the tree
tags = tags or set("*")
for tag in tags:
selector = tagView on GitHub (pinned to 5d213a2d47)
Solutions
- Add the element parameter to the callable: def keep(s): return s.attrib.get('data-ok') == '1'.
- If using functools.partial, ensure at least one positional slot remains free for the Selector.
- Note that builtins with optional-only args may also trip the signature check — wrap them in a lambda taking one argument.
Example fix
# before selector.find_all(lambda: True) # TypeError # after selector.find_all(lambda s: True)
Defensive patterns
Strategy: validation
Validate before calling
from inspect import signature
def takes_at_least_one_arg(fn) -> bool:
try:
return len(signature(fn).parameters) > 0
except (TypeError, ValueError):
return False
assert takes_at_least_one_arg(my_filter), 'filter must accept a Selector argument' Prevention
- Write filter callables as lambda s: ... from the start so the parameter is never forgotten.
- With functools.partial, leave at least one positional parameter unfilled for the Selector.
When it happens
Trigger: find_all(lambda: True) or find_all(some_zero_arg_function). Lambdas with one arg like lambda s: s.attrib.get('x') are fine.
Common situations: Refactoring a filter from a constant-returning helper; passing a functools.partial that consumed all positional arguments; passing a class's __init__-less instance method bound with no free parameters left.
Related errors
- strategy must be callable, got {type(strategy).__name__}
- You have to pass something to search with, like tag name(s),
- Nested Iterables are not accepted, only iterables of tag nam
- Nested dictionaries are not accepted, only string keys and s
- Argument with type "{type(arg)}" is not accepted, please rea
AI-assisted analysis of D4Vinci/Scrapling@5d213a2d47 (2026-08-14).
Data as JSON: /api/errors/37b6ae2a22313df0.
Report an issue: GitHub.