Skip to content

Extend Sig to cover even more builtins #30

Description

@thorwhalen

There's a set up already that handles map, print etc.

It uses a dict that maps names to signatures, which is used if a signature is not found.

I'm not 100% comfortable in doing this since:

  • builtins don't really have clear signatures (they can use overloading, so a single signature is not defined). For instance, iter could have two signatures: iter(iterable) or iter(callable, sentinel).
  • it's possible (but unlikely) that the signature of an object is not found, but their name is in this ledger

Even so, if we do have this convenient fallback, it's not catching everything because sometime objects don't have a __name__.
Should we use a more flexible name_of_obj for this? Should we have this function also look for a name in the __doc__ (if so, we should check if all __doc__ of builtins start with the name of the object.

And do we use what's in the doc as far as signatures or define a signature that might make more sense.

See itemgetter for example. Perhaps the (*keys) signature might make more sense.
But then itemgetter(i, j,...) produces an operator.itemgetter instance that is callable, but doesn't have a signature. The signature that would make sense for it might be (sequence) (though note that all an input object needs to be here is "gettable", i.e. have a __getitem__ -- Sequence is the smallest collections type that is "gettable).

So how do we (and do we in the first place) take care of such cases where a type doesn't have a signature, and it produces callable instances that don't have a signature either. signatures.py takes care of partial explicitly, because we consider it fundamental for doing functional programming. But what about itemgetter, attrgetter, etc. Is there a clean way we can cover many of these in a consistent way?

Important: Here, we should NOT:

  • touch the builtins or wrap them in anyway so that they're signature friendly (there is a case for this in The case for having some wrapped versions of builtins #33, but our current issue doesn't deal with that)
  • change what inspect.signature would give us, unless inspect.signature raises an error.
    The only thing we want to do is do something useful (like returning a valid, usable, signature in cases where inspect.signature fails to do so.

Related: issue #16.

Notes

inspect.signature docs mention (see Note):

Some callables may not be introspect-able in certain implementations of Python. For example, in CPython, some built-in functions defined in C provide no metadata about their arguments.

This led me to look into pypy. Namely, the source code of builtins, with the intention of parsing it to retrieve signatures to use in i2.signatures.

Note that we still need to be on the look out for overloading situations that don't have a single signature: For instance:

iter(iterable) -> iterator
iter(callable, sentinel) -> iterator

Observe that some of the python function definitions (e.g. the builtin/operation module) have space as their first argument, which apparently should be ignored when retrieving the signature.

The signature for iter in pypy is:

(space, w_collection_or_callable, w_sentinel=None)

┆Issue is synchronized with this Asana task by Unito

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions