Skip to content

Fix curry/rcurry/autocurry crashing on unbound built-in methods - #167

Closed
binggao1230 wants to merge 1 commit into
Suor:masterfrom
binggao1230:fix-builtin-method-descriptor-curry
Closed

binggao1230 wants to merge 1 commit into
Suor:masterfrom
binggao1230:fix-builtin-method-descriptor-curry

Conversation

@binggao1230

Copy link
Copy Markdown

Problem

curry(), rcurry(), and autocurry() crash with ValueError when passed
an unbound method of a built-in type such as str.endswith, str.startswith,
or list.append:

>>> from funcy import rcurry
>>> has_suffix = rcurry(str.endswith)
# ValueError: Unable to introspect str.endswith() arguments

These functions are method_descriptor objects. inspect.signature() cannot
introspect them on CPython, and the fallback in get_spec() raised
unconditionally. Workaround was to pass n= explicitly (rcurry(str.endswith, 2)),
but that shouldn't be required. Reported in #108.

Fix

method_descriptor objects always expose __objclass__ (the class they belong
to). When signature() raises and __objclass__ is set, fall back to a
two-positional-argument spec — one for the implicit self and one for the
primary method argument. This covers the common use-case:

has_suffix = rcurry(str.endswith)   # no n= needed
has_suffix('.py')('file.py')        # True

starts_with_hello = rcurry(str.startswith)
starts_with_hello('Hello')('Hello World')  # True

Methods that need a different arity can still use the explicit n= form.

Changes

  • funcy/_inspect.py: handle __objclass__ in the signature() except branch
  • tests/test_funcs.py: add test_curry_builtin_method covering the new behaviour

All 206 tests pass.

Unbound methods of built-in types such as str.endswith, str.startswith,
and list.append are method_descriptor objects. inspect.signature() cannot
introspect them on CPython, so get_spec() raised ValueError even when the
caller did not supply an explicit n=.

Detect this case via __objclass__ (present on all method_descriptor objects)
and fall back to a two-positional-argument spec, which matches the most
common use-case: self plus one required argument. Callers that need a
different arity can still pass n= explicitly.

Fixes Suor#108.
@Suor

Suor commented Jun 24, 2026

Copy link
Copy Markdown
Owner

What about other methods, which have more than one argument besides self? This code will try to make them 2 args curry too.

Also, comments are two verbose. Please prepare a proper PR, not just what coding agent does without much thinking.

@binggao1230

Copy link
Copy Markdown
Author

You're right. This fallback is not a proper fix: it treats every non-introspectable builtin method descriptor as if n=2, which is not generally true, and even the motivating str.endswith case has optional start/end parameters. I also saw the older issue discussion recommending explicit n rather than partial builtin-method introspection.

I'm closing this PR rather than pushing a narrow/incorrect heuristic further.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants