i2mint / i2

Python Mint creation, manipulation, and use
Apache License 2.0
1 stars 1 forks source link

Extend `Sig` to cover even more builtins #30

Open thorwhalen opened 2 years ago

thorwhalen commented 2 years ago

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:

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:

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

sylvainbonnot commented 2 years ago

Here are some more cases where no single signature can be defined for a builtin (without wrapping the builtin):

bytearray(12) #this works
bytearray('word') #if string, needs a second argument 'decoding'
>>> TypeError: string argument without an encoding