Context locals¶
Want desired context’s locals¶
From a module function, get the locals and return value
When testing and an Exception occurs, the locals are only available in the context of where the error occurred, not necessarily where need to debug.
As you read this, keep in mind
To understand our motivation, how badly we want to see those locals, background on those locals:
param_a – Satoshi Nakamoto’s private key to the genesis block
param_b – the passphrase to that private key
^^ is exactly how it feels when don’t have access to those locals and then suddenly do!
—Betty White <– everything is attributed to her
Limited to:
module function; not a: class method, Generator, Iterator, or Iterable
function must end in a single
returnstatement; notyield,yield from, orraise
And wait! There’s more¶
In return, value can be: normal or tuple (packed values)
Wow!
Great!
Yea!
One return value example¶
Example function found in logging_strict.tech_niques.context_locals.
Lets pretend this is the module level function would like to see the locals
def _func(param_a: str, param_b: Optional[int] = 10) -> str:
param_a = f"Hey {param_a}" # Local only
param_b += 20 # Local only
return "bar"
So there are two locals we’d really really like to see:
param_a
param_b
Returns "bar"
from logging_strict.tech_niques.context_locals import get_locals_dynamic, _func
def main():
# If in same script file try, f"{__name__}._func"
func_path = f"logging_strict.tech_niques.context_locals._func"
args = ("A",)
kwargs = {}
t_ret = get_locals_dynamic(_func, *args, **kwargs)
ret, d_locals = t_ret
assert ret == "bar"
assert "param_a" in d_locals.keys()
assert "param_b" in d_locals.keys()
print(d_locals)
main()
{'full_name': '_func', 'param_a': 'Hey A', 'param_b': 30}
Woooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo- oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooah!
Note
__name__ is also your friend
This technique requires the absolute dotted path to the module
function. if in the same (python script) file, use
f"{__name__}.myfunc" instead.
Useful knowhow, if the module function is in the same file as a unittest
Caution
Especially applies to JSON
tl;dr;
In a str, preserve escape characters, use raw string, e.g. r”\\n”
“\\n” –> “\n”
Unpreserved, ^^ may happen
Escape characters need to be preserved. JSON str is an example where a raw string would preserve the escaped characters and remain valid JSON.
See also
Module private variables
- logging_strict.tech_niques.context_locals.__all__: tuple[str, str, str] = ("get_locals", "get_locals_dynamic", "FuncWrapper")¶
This modules exports
- logging_strict.tech_niques.context_locals._P: ParamSpec = typing_extensions.ParamSpec('_P')¶
Equivalent to
Any
Module objects
- class logging_strict.tech_niques.context_locals.FuncWrapper(func)¶
Bases:
objectWraps a function to provide basic info about it.
- Variables:
func ((types.FunctionType | types.MethodType | types.BuiltinFunctionType | types.BuiltinMethodType | types.WrapperDescriptorType | types.MethodWrapperType | types.MethodDescriptorType | types.ClassMethodDescriptorType)) – the function to wrap
See also
Source code source https://gist.github.com/jwcompdev/65da6a59a6bcb44864de77b8a29baeed
Conversation source https://stackoverflow.com/a/25959545
- static _get_method_parent(meth)¶
Returns the class of the parent of the specified method.
- property cls¶
Returns the function’s parent class.
- Returns:
the parent class
- Return type:
type | None
- property cls_name¶
Returns the function’s parent class name.
- Returns:
the parent class name
- Return type:
str | None
- property full_name¶
Returns the function’s full name with the class included.
- Returns:
the full name
- Return type:
- get_dotted_path()¶
Returns the function’s full path with class and package name.
- Returns:
the full path
- Return type:
- Raises:
ModuleNotFoundError– Cannot determine func module path
- property module¶
Returns the function’s parent module.
- Returns:
the parent module
- Return type:
types.ModuleType | None
- property module_filename¶
Returns the function’s module filename.
- Returns:
the module filename
- Return type:
str | None
- property module_name¶
Returns the function’s parent module name.
- Returns:
the parent module name
- Return type:
str | None
- property package_name¶
Returns the function’s package name.
- Returns:
the package name
- Return type:
- logging_strict.tech_niques.context_locals.get_locals(func_path, func, /, *args, **kwargs)¶
Uses
patchto retrieve the tested functions locals and return value!See this module docs for example
Limitation: the function must end with a single
return, notyieldorraise.- Parameters:
func¶ (collections.abc.Callable[logging_strict.tech_niques.context_locals._T, Any]) – The func
args¶ (ParamSpecArgs) – Positional arguments
kwargs¶ (ParamSpecKwargs) – Optional (keyword) arguments
- Returns:
Tuple containing return value and the locals
- Return type:
tuple[logging_strict.tech_niques.context_locals._T, dict[str, Any]]
Deprecated since version 1.6.0: get_locals_dynamic does not need func_path and has support for class methods.
Removal not planned. Very popular, widely used, transition low priority and will take time.
- logging_strict.tech_niques.context_locals.get_locals_dynamic(func, /, *args, **kwargs)¶
Uses
patchto retrieve the tested functions locals and return value!See this module docs for example
Limitation: the function must end with a single
return, notyieldorraise.- Parameters:
func¶ (collections.abc.Callable[logging_strict.tech_niques.context_locals._T, Any]) – The func
args¶ (ParamSpecArgs) – Positional arguments
kwargs¶ (ParamSpecKwargs) – Optional (keyword) arguments
- Returns:
Tuple containing return value and the locals
- Return type:
tuple[logging_strict.tech_niques.context_locals._T, dict[str, Any]]