diag_msg.py module.

1. diag_msg

With diag_msg you can print messages with the time and caller info added automatically. The default time format is H:M:S.f. The caller info includes the module name, class name (or null), method name (or null), and the line number relative to the start of the module.

Example:

print a diagnostic message

>>> from scottbrian_utils.diag_msg import diag_msg
>>> diag_msg('this is a diagnostic message')
16:20:05.909260 <input>:1 this is a diagnostic message

Note that the examples are done as if entered in a python session from the console. As such, the module name will show as <input>. When coded in a module, however, you will see the module name instead of <input>.

class diag_msg.CallerInfo(mod_name: str, cls_name: str, func_name: str, line_num: int)

NamedTuple for the caller info used in diag_msg.

Create new instance of CallerInfo(mod_name, cls_name, func_name, line_num)

cls_name: str

Alias for field number 1

func_name: str

Alias for field number 2

line_num: int

Alias for field number 3

mod_name: str

Alias for field number 0

diag_msg.diag_msg(*args, depth=1, dt_format='%H:%M:%S.%f', **kwargs)

Print diagnostic message.

Parameters:
  • args (Any) – the text to print as part of the diagnostic message

  • depth (int) – specifies how many callers to include in the call sequence

  • dt_format (str) – datetime format to use

  • kwargs (Any) – keyword args to pass along to the print statement

Example:

print a diagnostic message from a method with a seq depth of 2

Return type:

None

>>> from scottbrian_utils.diag_msg import diag_msg
>>> class Cls1:
...     @classmethod
...     def f1(cls, x):
...         # limit to two calls
...         diag_msg('diagnostic info', x, depth=2)
>>> Cls1.f1(42)
16:20:05.909260 <input>:1 -> <input>::Cls1.f1:5 diagnostic info 42
Example:

print a diagnostic message with different datetime format

>>> from scottbrian_utils.diag_msg import diag_msg
>>> class Cls1:
...     def f1(self, x):
...         # use different datetime format
...         diag_msg('diagnostic info',
...                  x,
...                  dt_format='%a %b-%d %H:%M:%S')
>>> Cls1().f1(24)
Tue Feb-16 10:38:32 <input>::Cls1.f1:4 diagnostic info 24
diag_msg.get_caller_info(frame)

Return caller information from the given stack frame.

Parameters:

frame (FrameType) – the frame from which to extract caller info

Return type:

CallerInfo

Returns:

The caller module name, class name (or null), function name (or null), and the line number within the module source

Example:

get caller info for current frame

>>> from scottbrian_utils.diag_msg import get_caller_info
>>> import inspect
>>> from os import fspath
>>> from pathlib import Path
>>> def f1():
...     a_frame = inspect.currentframe()
...     caller_info = get_caller_info(a_frame)
...     print(f'{caller_info.mod_name=}')
...     print(f'{caller_info.cls_name=}')
...     print(f'{caller_info.func_name=}')
...     print(f'{caller_info.line_num=}')
>>>
>>> f1()
caller_info.mod_name='<input>'
caller_info.cls_name=''
caller_info.func_name='f1'
caller_info.line_num=3
diag_msg.get_formatted_call_sequence(latest=0, depth=3)

Return a formatted string showing the callers.

Parameters:
  • latest (int) – specifies the stack position of the most recent caller to be included in the call sequence

  • depth (int) – specifies how many callers to include in the call sequence

Return type:

str

Returns:

Formatted string showing for each caller the module name, possibly a function name or a class name/method_name pair, and the source code line number. There are three basic scenarios:

  • A call from a script will appear as: mod_name:lineno

  • A call from a function will appear as: mod_name::func_name:lineno

  • A call from a class method will appear as:: mod_name::cls_name.func_name:lineno

This function is useful if, for example, you want to include the call sequence in a log.

Example:

get call sequence for three callers

>>> from scottbrian_utils.diag_msg import (
...     get_formatted_call_sequence)
>>> def f1():
...     # f1 now on stack
...     # call f2
...     f2()
>>> def f2():
...     # call f3
...     f3()
>>> def f3():
...     # f3 now latest entry in call sequence
...     # default is to get three most recent calls
...     print(get_formatted_call_sequence())
>>> f1()
<input>::f1:4 -> <input>::f2:3 -> <input>::f3:4

Note that when coded in a module, you will get the module name in the sequence instead of <input>, and the line numbers will be relative from the start of the module instead of from each of the function definition sections.

Example:

get call sequence for last two callers

>>> from scottbrian_utils.diag_msg import (
...     get_formatted_call_sequence)
>>> def f1():
...     # f1 now on stack
...     # call f2
...     f2()
>>> def f2():
...     # call f3
...     f3()
>>> def f3():
...     # f3 now latest entry in call sequence
...     # specify depth to get two most recent calls
...     call_seq = get_formatted_call_sequence(depth=2)
...     print(call_seq)
>>> f1()
<input>::f2:3 -> <input>::f3:4
Example:

get call sequence for two callers, one caller back

>>> from scottbrian_utils.diag_msg import (
...     get_formatted_call_sequence)
>>> def f1():
...     # f1 now on stack
...     # call f2
...     f2()
>>> def f2():
...     # call f3
...     f3()
>>> def f3():
...     # f3 now latest entry in call sequence
...     # specify latest to go back 1 and thus ignore f3
...     # specify depth to get two calls from latest going back
...     call_seq = get_formatted_call_sequence(latest=1, depth=2)
...     print(call_seq)
>>> f1()
<input>::f1:4 -> <input>::f2:3
Example:

get sequence for script call to class method

>>> from scottbrian_utils.diag_msg import (
...     get_formatted_call_sequence)
>>> class Cls1:
...     def f1(self):
...         # limit to two calls
...         call_seq = get_formatted_call_sequence(depth=2)
...         print(call_seq)
>>> a_cls1 = Cls1()
>>> a_cls1.f1()
<input>:1 -> <input>::Cls1.f1:4