Skip to content

Fix: get_spec() in funcy/_inspect.py looked up manual arg-spec overrides... - #176

Open
M001N wants to merge 1 commit into
Suor:masterfrom
M001N:oss-engine/d5f45d4f-ab33bf05
Open

Fix: get_spec() in funcy/_inspect.py looked up manual arg-spec overrides...#176
M001N wants to merge 1 commit into
Suor:masterfrom
M001N:oss-engine/d5f45d4f-ab33bf05

Conversation

@M001N

@M001N M001N commented Aug 16, 2026

Copy link
Copy Markdown

Summary

Extended the manual-override mechanism in funcy/_inspect.py: added a _spec_from_str() helper factoring out the existing spec-string-to-Spec parsing logic, and a new lookup keyed by func.__objclass__.__name__ (available on builtin method descriptors) checked alongside the existing module-keyed lookup in get_spec(). Added ARGS['str'] with entries for 'startswith' ('self,prefix') and 'endswith' ('self,suffix') -- the two methods that actually fail signature() introspection on modern CPython. Deliberately did not add str.split/replace/join since those already introspect correctly via signature() (verified: only startswith/endswith raise 'builtin has invalid signature' on this Python version) and adding overrides for them would have dropped their keyword-argument support (used by an existing autocurry(str.split) test), since the override mechanism doesn't track argument names.

Problem

Suor/funcy issue reference: #108

Root Cause

get_spec() in funcy/_inspect.py looked up manual arg-spec overrides only via mod = getattr(func, '__module__', None) against the module-keyed ARGS table. str.endswith is a method_descriptor with no module (falls back to None), so it never matched ARGS['builtins']. It also has no code and is not a type, so execution fell through to the final signature(func) call, which raises on this descriptor (no valid text_signature), and funcy re-raises that as a plain ValueError, masking a fixable introspection gap.

Testing

PASS - all 206 tests in the full suite pass, including the new regression test and all pre-existing curry/rcurry/autocurry tests.

Related Issue

#108

…swith

get_spec() only looked up manual arg-spec overrides by __module__, but
method descriptors of builtin types (e.g. str.endswith) have no
__module__, so it fell through to signature() which raises on descriptors
lacking a valid __text_signature__ -- turned into a bare ValueError.

Extend the override mechanism to also key off __objclass__.__name__ (the
owning builtin type), analogous to the existing module-keyed ARGS table,
and add entries for str.startswith/str.endswith.

Fixes Suor#108
Comment thread funcy/_inspect.py
# keyed by the owning type's name (func.__objclass__.__name__), mirroring how
# ARGS[mod] works for module-level builtins above. These cover builtin methods
# whose __text_signature__ is missing/invalid, so signature() can't handle them.
ARGS['str'] = {

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be a separate namespace for this. Should look how much this is needed outside of str.endswith example

Comment thread funcy/_inspect.py
# whose __text_signature__ is missing/invalid, so signature() can't handle them.
ARGS['str'] = {
'startswith': 'self,prefix',
'endswith': 'self,suffix',

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They also have optional arguments

Comment thread funcy/_inspect.py
Spec = namedtuple("Spec", "max_n names req_n req_names varkw")


def _spec_from_str(_spec):

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should go after get_spec() - we have top-down order in this file

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