checkpointing.identifier.func_call.context
1import inspect 2from typing import List, Dict, Tuple, Callable, Any, Union 3from collections import OrderedDict 4from checkpointing._typing import ReturnValue 5from types import FrameType 6import copy 7 8 9class FuncCallContext: 10 """ 11 Context of information for a function call. 12 """ 13 14 def __init__(self, func: Callable[..., ReturnValue], args: Tuple, kwargs: Dict, def_frame: FrameType = None,) -> None: 15 """ 16 Args: 17 func: the function object that is being called 18 args: the non-keywords arguments of the function call 19 kwargs: the keyword arguments of the function call 20 def_frame: the frame where the function is defined 21 """ 22 23 self.__func: Callable[..., ReturnValue] = func 24 self.__args: Tuple = args 25 self.__kwargs: Dict = kwargs 26 self.__signature = inspect.signature(self.__func) 27 28 if def_frame is not None: 29 self.__locals = copy.copy(def_frame.f_locals) 30 31 else: 32 self.__locals = None 33 34 @property 35 def arguments(self) -> Dict: 36 """ 37 Dictionary of the function arguments and their actually applied parameter values in the function call. 38 39 >>> def foo(a, b=1, c=None, d=4): 40 ... pass 41 >>> 42 >>> # Equivalent to the context computed for: foo(1, 2, c=3) 43 >>> ctx = FuncCallContext(foo, (1, 2), {"c": 3}) 44 >>> 45 >>> dict(ctx.arguments) 46 {'a': 1, 'b': 2, 'c': 3, 'd': 4} 47 48 The varargs and kwargs can also be captured: 49 50 >>> def bar(*args, **kwargs): 51 ... pass 52 >>> 53 >>> ctx = FuncCallContext(bar, (1, 2), {"c": 3}) 54 >>> 55 >>> ctx.arguments 56 {'args': (1, 2), 'kwargs': {'c': 3}} 57 """ 58 args = self.__signature.bind(*self.__args, **self.__kwargs) 59 args.apply_defaults() 60 return dict(args.arguments) 61 62 @property 63 def full_name(self) -> str: 64 """ 65 The full name of the function. 66 Specifically, the concatenation of a function's module and its [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name). 67 68 >>> def foo(): 69 ... pass 70 >>> 71 >>> # Equivalent to the context computed for: foo() 72 >>> ctx = FuncCallContext(foo, (), {}) 73 >>> 74 >>> # foo is defined in checkpointing/identifier/func_call/context.py 75 >>> ctx.full_name 76 'checkpointing.identifier.func_call.context.foo' 77 """ 78 return ".".join([self.module, self.qualified_name]) 79 80 @property 81 def module(self) -> str: 82 """ 83 Module where the function is defined. 84 85 >>> def foo(): 86 ... pass 87 >>> 88 >>> # Equivalent to the context computed for: foo() 89 >>> ctx = FuncCallContext(foo, (), {}) 90 >>> 91 >>> # foo is defined in checkpointing/identifier/func_call/context.py 92 >>> ctx.module 93 'checkpointing.identifier.func_call.context' 94 """ 95 96 return self.__func.__module__ 97 98 @property 99 def name(self) -> str: 100 """ 101 Name of the function. 102 103 >>> def foo(): 104 ... pass 105 >>> 106 >>> # Equivalent to the context computed for: foo() 107 >>> ctx = FuncCallContext(foo, (), {}) 108 >>> ctx.name 109 'foo' 110 """ 111 112 return self.__func.__name__ 113 114 @property 115 def qualified_name(self) -> str: 116 """ 117 [Qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the function. 118 119 >>> class Foo: 120 ... def bar(self): 121 ... pass 122 >>> 123 >>> f = Foo() 124 >>> 125 >>> # Equivalent to the context computed for: f.bar() 126 >>> ctx = FuncCallContext(f.bar, (), {}) 127 >>> ctx.qualified_name 128 'Foo.bar' 129 """ 130 131 return self.__func.__qualname__ 132 133 @property 134 def code(self) -> str: 135 r""" 136 The source code of the function, including the function signature, 137 formatted as-is, including any comments. 138 139 >>> def foo(a, b): 140 ... c = a + b # add a and b 141 ... return c 142 >>> 143 >>> # Equivalent to the context computed for: foo(1, 2) 144 >>> ctx = FuncCallContext(foo, (1, 2), {}) 145 >>> 146 >>> ctx.code 147 'def foo(a, b):\n c = a + b # add a and b\n return c\n' 148 """ 149 150 return inspect.getsource(self.__func) 151 152 def get_nonlocal_variable(self, varname: str) -> Any: 153 r""" 154 Try to get the nonlocal variable `varname` from the function call's 155 `locals()` and `globals()`. 156 If it doesn't exist in neither of them, return `None`. 157 If the caller_frame is not provided, the result is always `None`. 158 159 >>> import inspect 160 >>> 161 >>> a = 1 162 >>> def foo(): 163 ... pass 164 >>> 165 >>> ctx = FuncCallContext(foo, (), {}, inspect.currentframe()) 166 >>> ctx.get_nonlocal_variable("a") 167 1 168 >>> ctx.get_nonlocal_variable("b") is None 169 True 170 """ 171 172 if self.__locals is not None and varname in self.__locals: 173 return self.__locals[varname] 174 175 if self.__func.__globals__ is not None and varname in self.__func.__globals__: 176 return self.__func.__globals__[varname] 177 178 return None
class
FuncCallContext:
10class FuncCallContext: 11 """ 12 Context of information for a function call. 13 """ 14 15 def __init__(self, func: Callable[..., ReturnValue], args: Tuple, kwargs: Dict, def_frame: FrameType = None,) -> None: 16 """ 17 Args: 18 func: the function object that is being called 19 args: the non-keywords arguments of the function call 20 kwargs: the keyword arguments of the function call 21 def_frame: the frame where the function is defined 22 """ 23 24 self.__func: Callable[..., ReturnValue] = func 25 self.__args: Tuple = args 26 self.__kwargs: Dict = kwargs 27 self.__signature = inspect.signature(self.__func) 28 29 if def_frame is not None: 30 self.__locals = copy.copy(def_frame.f_locals) 31 32 else: 33 self.__locals = None 34 35 @property 36 def arguments(self) -> Dict: 37 """ 38 Dictionary of the function arguments and their actually applied parameter values in the function call. 39 40 >>> def foo(a, b=1, c=None, d=4): 41 ... pass 42 >>> 43 >>> # Equivalent to the context computed for: foo(1, 2, c=3) 44 >>> ctx = FuncCallContext(foo, (1, 2), {"c": 3}) 45 >>> 46 >>> dict(ctx.arguments) 47 {'a': 1, 'b': 2, 'c': 3, 'd': 4} 48 49 The varargs and kwargs can also be captured: 50 51 >>> def bar(*args, **kwargs): 52 ... pass 53 >>> 54 >>> ctx = FuncCallContext(bar, (1, 2), {"c": 3}) 55 >>> 56 >>> ctx.arguments 57 {'args': (1, 2), 'kwargs': {'c': 3}} 58 """ 59 args = self.__signature.bind(*self.__args, **self.__kwargs) 60 args.apply_defaults() 61 return dict(args.arguments) 62 63 @property 64 def full_name(self) -> str: 65 """ 66 The full name of the function. 67 Specifically, the concatenation of a function's module and its [qualified name](https://docs.python.org/3/glossary.html#term-qualified-name). 68 69 >>> def foo(): 70 ... pass 71 >>> 72 >>> # Equivalent to the context computed for: foo() 73 >>> ctx = FuncCallContext(foo, (), {}) 74 >>> 75 >>> # foo is defined in checkpointing/identifier/func_call/context.py 76 >>> ctx.full_name 77 'checkpointing.identifier.func_call.context.foo' 78 """ 79 return ".".join([self.module, self.qualified_name]) 80 81 @property 82 def module(self) -> str: 83 """ 84 Module where the function is defined. 85 86 >>> def foo(): 87 ... pass 88 >>> 89 >>> # Equivalent to the context computed for: foo() 90 >>> ctx = FuncCallContext(foo, (), {}) 91 >>> 92 >>> # foo is defined in checkpointing/identifier/func_call/context.py 93 >>> ctx.module 94 'checkpointing.identifier.func_call.context' 95 """ 96 97 return self.__func.__module__ 98 99 @property 100 def name(self) -> str: 101 """ 102 Name of the function. 103 104 >>> def foo(): 105 ... pass 106 >>> 107 >>> # Equivalent to the context computed for: foo() 108 >>> ctx = FuncCallContext(foo, (), {}) 109 >>> ctx.name 110 'foo' 111 """ 112 113 return self.__func.__name__ 114 115 @property 116 def qualified_name(self) -> str: 117 """ 118 [Qualified name](https://docs.python.org/3/glossary.html#term-qualified-name) of the function. 119 120 >>> class Foo: 121 ... def bar(self): 122 ... pass 123 >>> 124 >>> f = Foo() 125 >>> 126 >>> # Equivalent to the context computed for: f.bar() 127 >>> ctx = FuncCallContext(f.bar, (), {}) 128 >>> ctx.qualified_name 129 'Foo.bar' 130 """ 131 132 return self.__func.__qualname__ 133 134 @property 135 def code(self) -> str: 136 r""" 137 The source code of the function, including the function signature, 138 formatted as-is, including any comments. 139 140 >>> def foo(a, b): 141 ... c = a + b # add a and b 142 ... return c 143 >>> 144 >>> # Equivalent to the context computed for: foo(1, 2) 145 >>> ctx = FuncCallContext(foo, (1, 2), {}) 146 >>> 147 >>> ctx.code 148 'def foo(a, b):\n c = a + b # add a and b\n return c\n' 149 """ 150 151 return inspect.getsource(self.__func) 152 153 def get_nonlocal_variable(self, varname: str) -> Any: 154 r""" 155 Try to get the nonlocal variable `varname` from the function call's 156 `locals()` and `globals()`. 157 If it doesn't exist in neither of them, return `None`. 158 If the caller_frame is not provided, the result is always `None`. 159 160 >>> import inspect 161 >>> 162 >>> a = 1 163 >>> def foo(): 164 ... pass 165 >>> 166 >>> ctx = FuncCallContext(foo, (), {}, inspect.currentframe()) 167 >>> ctx.get_nonlocal_variable("a") 168 1 169 >>> ctx.get_nonlocal_variable("b") is None 170 True 171 """ 172 173 if self.__locals is not None and varname in self.__locals: 174 return self.__locals[varname] 175 176 if self.__func.__globals__ is not None and varname in self.__func.__globals__: 177 return self.__func.__globals__[varname] 178 179 return None
Context of information for a function call.
FuncCallContext( func: Callable[..., ~ReturnValue], args: Tuple, kwargs: Dict, def_frame: frame = None)
15 def __init__(self, func: Callable[..., ReturnValue], args: Tuple, kwargs: Dict, def_frame: FrameType = None,) -> None: 16 """ 17 Args: 18 func: the function object that is being called 19 args: the non-keywords arguments of the function call 20 kwargs: the keyword arguments of the function call 21 def_frame: the frame where the function is defined 22 """ 23 24 self.__func: Callable[..., ReturnValue] = func 25 self.__args: Tuple = args 26 self.__kwargs: Dict = kwargs 27 self.__signature = inspect.signature(self.__func) 28 29 if def_frame is not None: 30 self.__locals = copy.copy(def_frame.f_locals) 31 32 else: 33 self.__locals = None
Args
- func: the function object that is being called
- args: the non-keywords arguments of the function call
- kwargs: the keyword arguments of the function call
- def_frame: the frame where the function is defined
arguments: Dict
Dictionary of the function arguments and their actually applied parameter values in the function call.
>>> def foo(a, b=1, c=None, d=4):
... pass
>>>
>>> # Equivalent to the context computed for: foo(1, 2, c=3)
>>> ctx = FuncCallContext(foo, (1, 2), {"c": 3})
>>>
>>> dict(ctx.arguments)
{'a': 1, 'b': 2, 'c': 3, 'd': 4}
The varargs and kwargs can also be captured:
>>> def bar(*args, **kwargs):
... pass
>>>
>>> ctx = FuncCallContext(bar, (1, 2), {"c": 3})
>>>
>>> ctx.arguments
{'args': (1, 2), 'kwargs': {'c': 3}}
full_name: str
The full name of the function. Specifically, the concatenation of a function's module and its qualified name.
>>> def foo():
... pass
>>>
>>> # Equivalent to the context computed for: foo()
>>> ctx = FuncCallContext(foo, (), {})
>>>
>>> # foo is defined in checkpointing/identifier/func_call/context.py
>>> ctx.full_name
'checkpointing.identifier.func_call.context.foo'
module: str
Module where the function is defined.
>>> def foo():
... pass
>>>
>>> # Equivalent to the context computed for: foo()
>>> ctx = FuncCallContext(foo, (), {})
>>>
>>> # foo is defined in checkpointing/identifier/func_call/context.py
>>> ctx.module
'checkpointing.identifier.func_call.context'
name: str
Name of the function.
>>> def foo():
... pass
>>>
>>> # Equivalent to the context computed for: foo()
>>> ctx = FuncCallContext(foo, (), {})
>>> ctx.name
'foo'
qualified_name: str
Qualified name of the function.
>>> class Foo:
... def bar(self):
... pass
>>>
>>> f = Foo()
>>>
>>> # Equivalent to the context computed for: f.bar()
>>> ctx = FuncCallContext(f.bar, (), {})
>>> ctx.qualified_name
'Foo.bar'
code: str
The source code of the function, including the function signature, formatted as-is, including any comments.
>>> def foo(a, b):
... c = a + b # add a and b
... return c
>>>
>>> # Equivalent to the context computed for: foo(1, 2)
>>> ctx = FuncCallContext(foo, (1, 2), {})
>>>
>>> ctx.code
'def foo(a, b):\n c = a + b # add a and b\n return c\n'
def
get_nonlocal_variable(self, varname: str) -> Any:
153 def get_nonlocal_variable(self, varname: str) -> Any: 154 r""" 155 Try to get the nonlocal variable `varname` from the function call's 156 `locals()` and `globals()`. 157 If it doesn't exist in neither of them, return `None`. 158 If the caller_frame is not provided, the result is always `None`. 159 160 >>> import inspect 161 >>> 162 >>> a = 1 163 >>> def foo(): 164 ... pass 165 >>> 166 >>> ctx = FuncCallContext(foo, (), {}, inspect.currentframe()) 167 >>> ctx.get_nonlocal_variable("a") 168 1 169 >>> ctx.get_nonlocal_variable("b") is None 170 True 171 """ 172 173 if self.__locals is not None and varname in self.__locals: 174 return self.__locals[varname] 175 176 if self.__func.__globals__ is not None and varname in self.__func.__globals__: 177 return self.__func.__globals__[varname] 178 179 return None
Try to get the nonlocal variable varname from the function call's
locals() and globals().
If it doesn't exist in neither of them, return None.
If the caller_frame is not provided, the result is always None.
>>> import inspect
>>>
>>> a = 1
>>> def foo():
... pass
>>>
>>> ctx = FuncCallContext(foo, (), {}, inspect.currentframe())
>>> ctx.get_nonlocal_variable("a")
1
>>> ctx.get_nonlocal_variable("b") is None
True