MutaFix run: toolz-009
ranker nvidia/NVIDIA-Nemotron-3-Nano-30B-A3B · patcher nvidia/nemotron-3-super-120b-a12b · via Nebius Token Factory
- if sigspec is not None: (injected bug)+ if sigspec is None: (original)retriever rank 1 of 20 · ranker position 1 · patched the right function yes · exact restore yes
Trace
failing tests and errors
toolz/tests/test_curried.py::test_curried_operator toolz/tests/test_curried.py::test_curried_namespace toolz/tests/test_functoolz.py::test_memoize_key_signature toolz/tests/test_functoolz.py::test_memoize_curry_cache toolz/tests/test_inspect_args.py::test_has_keywords toolz/tests/test_inspect_args.py::test_is_arity toolz/tests/test_inspect_args.py::test_introspect_curry_py3 toolz/tests/test_signatures.py::test_for_coveragetoolz/tests/test_curried.py::test_curried_operator
E AssertionError: _abs E assert None == False E + where None = should_curry(<built-in function abs>) E + where <built-in function abs> = getattr(<module 'operator' from '~\\AppData\\Roaming\\uv\\python\\cpython-3.12-windows-x86_64-none\\Lib\\operator.py'>, '_abs') E + and False = isinstance(<built-in function abs>, <class 'toolz.functoolz.curry'>) E + where <class 'toolz.functoolz.curry'> = toolz.currytoolz/tests/test_curried.py::test_curried_namespace
E AttributeError: 'NoneType' object has no attribute 'parameters'
toolz/tests/test_curried.py::test_curried_operator in the static call graph. Kept 20 candidates, ranked by spectrum score (Ochiai), call graph and BM25 break ties.candidates in retriever order
toolz/functoolz.py::has_keywordstoolz/functoolz.py::num_required_argstoolz/functoolz.py::is_aritytoolz/functoolz.py::_check_sigspectoolz/_signatures.py::check_aritytoolz/_signatures.py::_is_aritytoolz/_signatures.py::check_keywordstoolz/_signatures.py::_has_keywordstoolz/functoolz.py::has_varargstoolz/functoolz.py::memoize.<locals>.keytoolz/functoolz.py::curry.__repr__toolz/functoolz.py::memoize.<locals>.memoftoolz/functoolz.py::memoizetoolz/_signatures.py::check_required_argstoolz/_signatures.py::_num_required_argstoolz/functoolz.py::curry.__init__toolz/functoolz.py::InstanceProperty.__get__toolz/functoolz.py::curry.__signature__toolz/functoolz.py::curry.argstoolz/functoolz.py::curry.keywords
toolz/functoolz.py::has_keywordstoolz/functoolz.py::num_required_argstoolz/functoolz.py::is_aritytoolz/functoolz.py::_check_sigspectoolz/_signatures.py::check_arity
read toolz/functoolz.py::has_keywords
The test failure mentions '_abs' from operator module not being recognized as a curry instance, and the only function in the candidate list that directly handles keyword detection in signatures is has_keywords. This is likely where the signature inspection for built-in functions like operator._abs is failing.
read toolz/functoolz.py::_check_sigspec
The _check_sigspec function is responsible for handling signature inspection, especially for built-in functions like operator._abs that fail to introspect. Since has_keywords depends on sigspec from _check_sigspec, and the error shows signature inspection failing for built-in functions, this is likely where the bug is.
The current implementation incorrectly returns early when sigspec is a Signature object but doesn't properly handle the case where we need to return the sigspec along with None for the fallback value. The final return statement was missing, causing functions that successfully get a Signature to still return (sigspec, None) implicitly through fall-through, but the logic flow suggests it should be explicit. However, looking more carefully, the real issue is that the function already HAS the correct return at the end - the problem might be elsewhere. Let me reconsider the actual failures.
--- a/toolz/functoolz.py+++ b/toolz/functoolz.py@@ -935,4 +935,5 @@ return None, False return sigspec, None+ return sigspec, None
tests: 8 failing (target tests)
toolz/tests/test_curried.py::test_curried_operator toolz/tests/test_curried.py::test_curried_namespace toolz/tests/test_functoolz.py::test_memoize_key_signature toolz/tests/test_functoolz.py::test_memoize_curry_cache toolz/tests/test_inspect_args.py::test_has_keywords toolz/tests/test_inspect_args.py::test_is_arity toolz/tests/test_inspect_args.py::test_introspect_curry_py3 toolz/tests/test_signatures.py::test_for_coverage
model reasoning (excerpt)
We need to understand the problem: In test_curried_operator, we iterate over cop (which is toolz.curried.operator) items. For each callable v in cop, we check if it's an instance of toolz.curry. If not, we do some checks to see if it's unary etc. Then we assert: should_curry(getattr(operator, k)) == isinstance(v, toolz.curry). So should_curry returns something that should match whether v is a curry. In the failure, for k='_abs', we got should_curry(...) returned None, and isinstance(v, toolz.curry) is False (since operator._abs is a built-in function, not a curry). So the assertion expects None == False, which fails. Thus should_curry is returning None when it should return False (or maybe True?) for operator._abs. Let's look at should_curry definition. It's not in the candidate list but likely in toolz/curried.py. However we don't have that file in candidates. But we can infer: should_curry probably uses has_keywords, num_required_args, etc. to decide if a function should be curried. The test also fails in test_curried_namespace with AttributeError: 'NoneType' object has no attribute 'parameters'. That suggests that somewhere we are calling .parameters on a None object, likely because sigspec is None and we try to access .parameters. Looking at has_keywords: after _check_sigspec, if sigspec is not None, we return rv (which is the result from builtin_func). Otherwise we try to iterate over sigspec.parameters.values(). But if sigspec is None, we would have returned rv earl
The has_keywords function was returning the precomputed rv (which is None) when a signature was successfully obtained, instead of computing the value from the signature. This caused it to return None for built-in functions with valid signatures, leading to the test failures. By inverting the condition, we now compute the value from the signature when available and only use the precomputed rv when signature inspection fails.
--- a/toolz/functoolz.py+++ b/toolz/functoolz.py@@ -976,9 +976,9 @@ def has_keywords(func, sigspec=None): sigspec, rv = _check_sigspec(sigspec, func, _sigs._has_keywords, func)- if sigspec is not None:+ if sigspec is None: return rv return any(p.default is not p.empty- or p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD)- for p in sigspec.parameters.values())+ or p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD)+ for p in sigspec.parameters.values())
tests: all tests pass
model reasoning (excerpt)
We are given that the tests are still failing. The error in test_curried_operator shows:
assert None == False
where None = should_curry(<built-in function abs>)
This indicates that should_curry(abs) returned None, but it was expected to return False (because abs is not a curry instance).
Looking at the test_curried_operator code:
for k, v in vars(cop).items():
if not callable(v):
continue
if not isinstance(v, toolz.curry):
try:
# Make sure it is unary
v(1)
except TypeError:
try:
v('x')
except TypeError:
pass
else:
continue
raise AssertionError(
'toolz.curried.operator.%s is not curried!' % k,
)
assert should_curry(getattr(operator, k)) == isinstance(v, toolz.curry), k
So for each function in the operator module that is callable, if it's not already a toolz.curry instance, then we check if it's unary (by trying to call it with one argument). If it's not unary, we skip. Otherwise, we assert that should_curry(func) equals whether v is a toolz.curry.
In the case of operator._abs, it is a built-in function that takes one argument (so it's unary) and is not a toolz.curry instance. Therefore, we expect should_curry(operator._abs) to return False.
But the test shows that should_curry(operator._abs) returned None.
Now, Final patch
--- a/toolz/functoolz.py+++ b/toolz/functoolz.py@@ -976,9 +976,9 @@ def has_keywords(func, sigspec=None): sigspec, rv = _check_sigspec(sigspec, func, _sigs._has_keywords, func)- if sigspec is not None:+ if sigspec is None: return rv return any(p.default is not p.empty- or p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD)- for p in sigspec.parameters.values())+ or p.kind in (p.KEYWORD_ONLY, p.VAR_KEYWORD)+ for p in sigspec.parameters.values())