0002_signature_from_callable

Expand cell

# from IPython.core.display import display, HTML # a depreciated import
from IPython.display import display, HTML
display(HTML("<style>.container { width:100% !important; }</style>"))

Imports and initiate

from fastdebug.core import *
from fastcore.meta import *
g = locals()
fdb = Fastdb(inspect._signature_from_callable, outloc=g)
fdbF = Fastdb(FixSigMeta, outloc=g)

Examples

from fastdebug.utils import whatinside
inspect._signature_from_callable(whatinside, sigcls=inspect.Signature)
<Signature (mo, dun: bool = False, func: bool = False, clas: bool = False, bltin: bool = False, lib: bool = False, cal: bool = False)>
fdb.eg = "inspect._signature_from_callable(whatinside, sigcls=inspect.Signature)"

fdb.eg = """
class Base: # pass
    def __new__(self, **args): pass  # defines a __new__ 

class Foo_new(Base):
    def __init__(self, d, e, f): pass
    
pprint(inspect._signature_from_callable(Foo_new, sigcls=inspect.Signature))
"""
fdb.eg = """
class Base: # pass
    def __new__(self, **args): pass  # defines a __new__ 

class Foo_new_fix(Base, metaclass=FixSigMeta):
    def __init__(self, d, e, f): pass
    
pprint(inspect._signature_from_callable(Foo_new_fix, sigcls=inspect.Signature))
"""

fdb.eg = """
class BaseMeta(type): 
    # using __new__ from type
    def __call__(cls, *args, **kwargs): pass
class Foo_call(metaclass=BaseMeta): 
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call, sigcls=inspect.Signature))
"""

fdbF.eg = """
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
"""

fdb.eg = """
class Foo_init:
    def __init__(self, a, b, c): pass

pprint(inspect._signature_from_callable(Foo_init, sigcls=inspect.Signature))
"""
fdbF.docsrc(2, "how does a metaclass create a class instance; what does super().__new__() do here;", "inspect.getdoc(super)")
fdbF.docsrc(4, "how to remove self from a signature; how to check whether a class' __init__ is inherited from object or not;",\
            "res", "res.__init__ is not object.__init__")
fdbF.docsrc(1, "Any class having FixSigMeta as metaclass will have its own __init__ func stored in its attr __signature__;\
FixSigMeta uses its __new__ to create a class instance; then check whether its class instance has its own __init__;\
if so, remove self from the sig of __init__; then assign this new sig to __signature__ for the class instance;")
========================================================     Investigating FixSigMeta     ========================================================
===============================================================     on line 2     ================================================================
     with example 
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
     

print selected srcline with expands below--------
class FixSigMeta(type):                                                                                                                                 (0)
    "A metaclass that fixes the signature on classes that override `__new__`"                                                                           (1)
    def __new__(cls, name, bases, dict):================================================================================================================(2)
                                                                           how does a metaclass create a class instance; what does super().__new__() do here;
        res = super().__new__(cls, name, bases, dict)                                                                                                   (3)
        if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__))                                           (4)

==================================================================================================================Start of my srcline exploration:


inspect.getdoc(super) => inspect.getdoc(super) : super() -> same as super(__class__, <first argument>)
super(type) -> unbound super object
super(type, obj) -> bound super object; requires isinstance(obj, type)
super(type, type2) -> bound super object; requires issubclass(type2, type)
Typical use to call a cooperative superclass method:
class C(B):
    def meth(self, arg):
        super().meth(arg)
This works for class methods too:
class C(B):
    @classmethod
    def cmeth(cls, arg):
        super().cmeth(arg)
====================================================================================================================End of my srcline exploration:

<Signature (d, e, f)>

Review srcode with all comments added so far======================================================================================================
class FixSigMeta(type):===================================================================(0)       
    "A metaclass that fixes the signature on classes that override `__new__`"=============(1)       
    def __new__(cls, name, bases, dict):==================================================(2) # how does a metaclass create a class instance; what does super().__new__() do here;; 
        res = super().__new__(cls, name, bases, dict)=====================================(3)       
        if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__))                                           (4)
        return res========================================================================(5)       
                                                                                                                                                        (6)
                                                                                                                                     part No.1 out of 1 parts

========================================================     Investigating FixSigMeta     ========================================================
===============================================================     on line 4     ================================================================
     with example 
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
     

print selected srcline with expands below--------
    def __new__(cls, name, bases, dict):                                                                                                                (2)
        res = super().__new__(cls, name, bases, dict)                                                                                                   (3)
        if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__))===========================================(4)
                                                 how to remove self from a signature; how to check whether a class' __init__ is inherited from object or not;
        return res                                                                                                                                      (5)
                                                                                                                                                        (6)

==================================================================================================================Start of my srcline exploration:


                                                                                                                 res => res : <class '__main__.Foo_call_fix'>


                                                                            res.__init__ is not object.__init__ => res.__init__ is not object.__init__ : True
====================================================================================================================End of my srcline exploration:

<Signature (d, e, f)>

Review srcode with all comments added so far======================================================================================================
class FixSigMeta(type):===================================================================(0)       
    "A metaclass that fixes the signature on classes that override `__new__`"=============(1)       
    def __new__(cls, name, bases, dict):==================================================(2) # how does a metaclass create a class instance; what does super().__new__() do here;; 
        res = super().__new__(cls, name, bases, dict)=====================================(3)       
        if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__)) # how to remove self from a signature; how to check whether a class' __init__ is inherited from object or not;;  (4)
        return res========================================================================(5)       
                                                                                                                                                        (6)
                                                                                                                                     part No.1 out of 1 parts

========================================================     Investigating FixSigMeta     ========================================================
===============================================================     on line 1     ================================================================
     with example 
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
     

print selected srcline with expands below--------
class FixSigMeta(type):                                                                                                                                 (0)
    "A metaclass that fixes the signature on classes that override `__new__`"===========================================================================(1)
Any class having FixSigMeta as metaclass will have its own __init__ func stored in its attr __signature__;FixSigMeta uses its __new__ to create a class instance; then check whether its class instance has its own __init__;if so, remove self from the sig of __init__; then assign this new sig to __signature__ for the class instance;
    def __new__(cls, name, bases, dict):                                                                                                                (2)
        res = super().__new__(cls, name, bases, dict)                                                                                                   (3)
fdbF.snoop()
23:01:29.15 >>> Call to FixSigMeta.__new__ in File "/tmp/FixSigMeta.py", line 5
23:01:29.15 .......... cls = <class '__main__.BaseMeta'>
23:01:29.15 .......... name = 'Foo_call_fix'
23:01:29.15 .......... bases = ()
23:01:29.15 .......... dict = {'__module__': '__main__', '__qualname__': 'Foo_call_fix', '__init__': <function Foo_call_fix.__init__>}
23:01:29.15 .......... len(dict) = 3
23:01:29.15 .......... __class__ = <class 'fastcore.meta.FixSigMeta'>
23:01:29.15    5 |     def __new__(cls, name, bases, dict):
23:01:29.15    6 |         res = super().__new__(cls, name, bases, dict)
23:01:29.15 .............. res = <class '__main__.Foo_call_fix'>
23:01:29.15    7 |         if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__))
23:01:29.15    8 |         return res
23:01:29.15 <<< Return value from FixSigMeta.__new__: <class '__main__.Foo_call_fix'>
========================================================     Investigating FixSigMeta     ========================================================
==============================================================     on line None     ==============================================================
     with example 
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
     

<Signature (d, e, f)>
fdb.docsrc(29, "How to check whether a class has __signature__?", "hasattr(obj, '__signature__')")
fdb.docsrc(82, "how to check whether obj whose signature is builtins;", "inspect.getdoc(_signature_is_builtin)")
fdb.docsrc(7, "inspect.signature is calling inspect._signature_from_callable; \
create _get_signature_of using functools.partial to call on _signature_from_callable itself;\
obj is first tested for callable; then test obj for classmethod; then unwrap to the end unless obj has __signature__;\
if obj has __signature__, assign __signature__ to sig; then test obj for function, is true calling _signature_from_function; \
then test obj whose signature is builtins or not; test whether obj created by functools.partial; test obj is a class or not; \
if obj is a class, then check obj has its own __call__ first; then its own __new__; then its own __init__; then inherited __new__; \
finally inherited __init__; and then get sig from either of them by calling _get_signature_of on them; \
FixSigMeta assigns __init__ function to __signature__ attr for the instance class it creates; \
so that class with FixSigMeta as metaclass can have sig from __init__ through __signature__; \
no more worry about interference of sig from __call__ or __new__.")
=================================================     Investigating _signature_from_callable     =================================================
===============================================================     on line 29     ===============================================================
     with example 
class Foo_init:
    def __init__(self, a, b, c): pass

pprint(inspect._signature_from_callable(Foo_init, sigcls=inspect.Signature))
     

print selected srcline with expands below--------
    # Was this function wrapped by a decorator?                                                                                                         (27)
    if follow_wrapper_chains:                                                                                                                           (28)
        obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))=================================================================================(29)
                                                                                                              How to check whether a class has __signature__?
        if isinstance(obj, types.MethodType):                                                                                                           (30)
            # If the unwrapped object is a *method*, we might want to                                                                                   (31)

==================================================================================================================Start of my srcline exploration:


                                                                                       hasattr(obj, '__signature__') => hasattr(obj, '__signature__') : False
====================================================================================================================End of my srcline exploration:

<Signature (a, b, c)>

Review srcode with all comments added so far======================================================================================================
        sig = _get_signature_of(obj.__func__)=============================================(20)      
                                                                                                                                                        (21)
        if skip_bound_arg:================================================================(22)      
            return _signature_bound_method(sig)===========================================(23)      
        else:=============================================================================(24)      
            return sig====================================================================(25)      
                                                                                                                                                        (26)
    # Was this function wrapped by a decorator?===========================================(27)      
    if follow_wrapper_chains:=============================================================(28)      
        obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))===================(29) # How to check whether a class has __signature__?; 
        if isinstance(obj, types.MethodType):=============================================(30)      
            # If the unwrapped object is a *method*, we might want to=====================(31)      
            # skip its first parameter (self).============================================(32)      
            # See test_signature_wrapped_bound_method for details.========================(33)      
            return _get_signature_of(obj)=================================================(34)      
                                                                                                                                                        (35)
    try:==================================================================================(36)      
        sig = obj.__signature__===========================================================(37)      
    except AttributeError:================================================================(38)      
        pass==============================================================================(39)      
                                                                                                                                    part No.2 out of 10 parts

=================================================     Investigating _signature_from_callable     =================================================
===============================================================     on line 82     ===============================================================
     with example 
class Foo_init:
    def __init__(self, a, b, c): pass

pprint(inspect._signature_from_callable(Foo_init, sigcls=inspect.Signature))
     

print selected srcline with expands below--------
                                        skip_bound_arg=skip_bound_arg)                                                                                  (80)
                                                                                                                                                        (81)
    if _signature_is_builtin(obj):======================================================================================================================(82)
                                                                                                        how to check whether obj whose signature is builtins;
        return _signature_from_builtin(sigcls, obj,                                                                                                     (83)
                                       skip_bound_arg=skip_bound_arg)                                                                                   (84)

==================================================================================================================Start of my srcline exploration:


inspect.getdoc(_signature_is_builtin) => inspect.getdoc(_signature_is_builtin) : Private helper to test if `obj` is a callable that might
support Argument Clinic's __text_signature__ protocol.
====================================================================================================================End of my srcline exploration:

<Signature (a, b, c)>

Review srcode with all comments added so far======================================================================================================
                                        skip_bound_arg=skip_bound_arg)====================(80)      
                                                                                                                                                        (81)
    if _signature_is_builtin(obj):========================================================(82) # how to check whether obj whose signature is builtins;; 
        return _signature_from_builtin(sigcls, obj,=======================================(83)      
                                       skip_bound_arg=skip_bound_arg)=====================(84)      
                                                                                                                                                        (85)
    if isinstance(obj, functools.partial):================================================(86)      
        wrapped_sig = _get_signature_of(obj.func)=========================================(87)      
        return _signature_get_partial(wrapped_sig, obj)===================================(88)      
                                                                                                                                                        (89)
    sig = None============================================================================(90)      
    if isinstance(obj, type):=============================================================(91)      
        # obj is a class or a metaclass===================================================(92)      
                                                                                                                                                        (93)
        # First, let's see if it has an overloaded __call__ defined=======================(94)      
        # in its metaclass================================================================(95)      
        call = _signature_get_user_defined_method(type(obj), '__call__')==================(96)      
        if call is not None:==============================================================(97)      
            sig = _get_signature_of(call)=================================================(98)      
        else:=============================================================================(99)      
                                                                                                                                    part No.5 out of 10 parts

=================================================     Investigating _signature_from_callable     =================================================
===============================================================     on line 7     ================================================================
     with example 
class Foo_init:
    def __init__(self, a, b, c): pass

pprint(inspect._signature_from_callable(Foo_init, sigcls=inspect.Signature))
     

print selected srcline with expands below--------
    """Private helper function to get signature for arbitrary                                                                                           (5)
    callable objects.                                                                                                                                   (6)
    """=================================================================================================================================================(7)
inspect.signature is calling inspect._signature_from_callable; create _get_signature_of using functools.partial to call on _signature_from_callable itself;obj is first tested for callable; then test obj for classmethod; then unwrap to the end unless obj has __signature__;if obj has __signature__, assign __signature__ to sig; then test obj for function, is true calling _signature_from_function; then test obj whose signature is builtins or not; test whether obj created by functools.partial; test obj is a class or not; if obj is a class, then check obj has its own __call__ first; then its own __new__; then its own __init__; then inherited __new__; finally inherited __init__; and then get sig from either of them by calling _get_signature_of on them; FixSigMeta assigns __init__ function to __signature__ attr for the instance class it creates; so that class with FixSigMeta as metaclass can have sig from __init__ through __signature__; no more worry about interference of sig from __call__ or __new__.
                                                                                                                                                        (8)
    _get_signature_of = functools.partial(_signature_from_callable,                                                                                     (9)
fdb.snoop()
23:01:29.21 >>> Call to _signature_from_callable in File "/tmp/_signature_from_callable.py", line 3
23:01:29.21 ...... obj = <class '__main__.Foo_init'>
23:01:29.21 ...... follow_wrapper_chains = True
23:01:29.21 ...... skip_bound_arg = True
23:01:29.21 ...... sigcls = <class 'inspect.Signature'>
23:01:29.21    3 | def _signature_from_callable(obj, *,
23:01:29.21   12 |     _get_signature_of = functools.partial(_signature_from_callable,
23:01:29.21   13 |                                 follow_wrapper_chains=follow_wrapper_chains,
23:01:29.21   14 |                                 skip_bound_arg=skip_bound_arg,
23:01:29.21   15 |                                 sigcls=sigcls)
23:01:29.21   12 |     _get_signature_of = functools.partial(_signature_from_callable,
23:01:29.21 .......... _get_signature_of = functools.partial(<function _signature_from_call...und_arg=True, sigcls=<class 'inspect.Signature'>)
23:01:29.21   17 |     if not callable(obj):
23:01:29.22   20 |     if isinstance(obj, types.MethodType):
23:01:29.22   31 |     if follow_wrapper_chains:
23:01:29.22   32 |         obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))
23:01:29.22   33 |         if isinstance(obj, types.MethodType):
23:01:29.22   39 |     try:
23:01:29.22   40 |         sig = obj.__signature__
=================================================     Investigating _signature_from_callable     =================================================
==============================================================     on line None     ==============================================================
     with example 
class Foo_init:
    def __init__(self, a, b, c): pass

pprint(inspect._signature_from_callable(Foo_init, sigcls=inspect.Signature))
     
23:01:29.35 !!! AttributeError: type object 'Foo_init' has no attribute '__signature__'
23:01:29.35 !!! When getting attribute: obj.__signature__
23:01:29.35   41 |     except AttributeError:
23:01:29.35   42 |         pass
23:01:29.35   51 |     try:
23:01:29.35   52 |         partialmethod = obj._partialmethod
23:01:29.36 !!! AttributeError: type object 'Foo_init' has no attribute '_partialmethod'
23:01:29.36 !!! When getting attribute: obj._partialmethod
23:01:29.36   53 |     except AttributeError:
23:01:29.36   54 |         pass
23:01:29.36   79 |     if isfunction(obj) or _signature_is_functionlike(obj):
23:01:29.36   85 |     if _signature_is_builtin(obj):
23:01:29.36   89 |     if isinstance(obj, functools.partial):
23:01:29.36   93 |     sig = None
23:01:29.36   94 |     if isinstance(obj, type):
23:01:29.36   99 |         call = _signature_get_user_defined_method(type(obj), '__call__')
23:01:29.36 .............. call = None
23:01:29.36  100 |         if call is not None:
23:01:29.36  103 |             factory_method = None
23:01:29.36  104 |             new = _signature_get_user_defined_method(obj, '__new__')
23:01:29.36 .................. new = None
23:01:29.36  105 |             init = _signature_get_user_defined_method(obj, '__init__')
23:01:29.36 .................. init = <function Foo_init.__init__>
23:01:29.36  107 |             if '__new__' in obj.__dict__:
23:01:29.36  110 |             elif '__init__' in obj.__dict__:
23:01:29.36  111 |                 factory_method = init
23:01:29.36 ...................... factory_method = <function Foo_init.__init__>
23:01:29.36  118 |             if factory_method is not None:
23:01:29.36  119 |                 sig = _get_signature_of(factory_method)
23:01:29.36 ...................... sig = <Signature (self, a, b, c)>
23:01:29.36  121 |         if sig is None:
23:01:29.36  170 |     if sig is not None:
23:01:29.36  173 |         if skip_bound_arg:
23:01:29.36  174 |             return _signature_bound_method(sig)
23:01:29.36 <<< Return value from _signature_from_callable: <Signature (a, b, c)>
<Signature (a, b, c)>
fdbF.print()
========================================================     Investigating FixSigMeta     ========================================================
==============================================================     on line None     ==============================================================
     with example 
class BaseMeta(FixSigMeta): 
    # using __new__ of  FixSigMeta instead of type
    def __call__(cls, *args, **kwargs): pass

class Foo_call_fix(metaclass=BaseMeta): # Base
    def __init__(self, d, e, f): pass

pprint(inspect._signature_from_callable(Foo_call_fix, sigcls=inspect.Signature))    
     

class FixSigMeta(type):===================================================================(0)       
    "A metaclass that fixes the signature on classes that override `__new__`"=============(1) # Any class having FixSigMeta as metaclass will have its own __init__ func stored in its attr __signature__;FixSigMeta uses its __new__ to create a class instance; then check whether its class instance has its own __init__;if so, remove self from the sig of __init__; then assign this new sig to __signature__ for the class instance;; 
    def __new__(cls, name, bases, dict):==================================================(2) # how does a metaclass create a class instance; what does super().__new__() do here;; 
        res = super().__new__(cls, name, bases, dict)=====================================(3)       
        if res.__init__ is not object.__init__: res.__signature__ = _rm_self(inspect.signature(res.__init__)) # how to remove self from a signature; how to check whether a class' __init__ is inherited from object or not;;  (4)
        return res========================================================================(5)       
                                                                                                                                                        (6)
fdb.print(30, 1)
def _signature_from_callable(obj, *,======================================================(0)       
                             follow_wrapper_chains=True,==================================(1)       
                             skip_bound_arg=True,=========================================(2)       
                             sigcls):=====================================================(3)       
                                                                                                                                                        (4)
    """Private helper function to get signature for arbitrary=============================(5)       
    callable objects.=====================================================================(6)       
    """===================================================================================(7) # inspect.signature is calling inspect._signature_from_callable; create _get_signature_of using functools.partial to call on _signature_from_callable itself;obj is first tested for callable; then test obj for classmethod; then unwrap to the end unless obj has __signature__;if obj has __signature__, assign __signature__ to sig; then test obj for function, is true calling _signature_from_function; then test obj whose signature is builtins or not; test whether obj created by functools.partial; test obj is a class or not; if obj is a class, then check obj has its own __call__ first; then its own __new__; then its own __init__; then inherited __new__; finally inherited __init__; and then get sig from either of them by calling _get_signature_of on them; FixSigMeta assigns __init__ function to __signature__ attr for the instance class it creates; so that class with FixSigMeta as metaclass can have sig from __init__ through __signature__; no more worry about interference of sig from __call__ or __new__.; 
                                                                                                                                                        (8)
    _get_signature_of = functools.partial(_signature_from_callable,=======================(9)       
                                follow_wrapper_chains=follow_wrapper_chains,==============(10)      
                                skip_bound_arg=skip_bound_arg,============================(11)      
                                sigcls=sigcls)============================================(12)      
                                                                                                                                                        (13)
    if not callable(obj):=================================================================(14)      
        raise TypeError('{!r} is not a callable object'.format(obj))======================(15)      
                                                                                                                                                        (16)
    if isinstance(obj, types.MethodType):=================================================(17)      
        # In this case we skip the first parameter of the underlying======================(18)      
        # function (usually `self` or `cls`).=============================================(19)      
        sig = _get_signature_of(obj.__func__)=============================================(20)      
                                                                                                                                                        (21)
        if skip_bound_arg:================================================================(22)      
            return _signature_bound_method(sig)===========================================(23)      
        else:=============================================================================(24)      
            return sig====================================================================(25)      
                                                                                                                                                        (26)
    # Was this function wrapped by a decorator?===========================================(27)      
    if follow_wrapper_chains:=============================================================(28)      
        obj = unwrap(obj, stop=(lambda f: hasattr(f, "__signature__")))===================(29) # How to check whether a class has __signature__?; 
                                                                                                                                     part No.1 out of 7 parts