Techniques¶
tech_niques which are logging related as well as code inspection
Conveniently exports all technique helpers
Module private variables
- logging_strict.tech_niques.__all__: tuple[str, str, str, str, str, str, str, str, str] = ("FuncWrapper", "get_locals", "get_locals_dynamic", "is_class_attrib_kind", "ClassAttribTypes", "LoggerRedirector", "captureLogs", "detect_coverage", "CaptureOutput")¶
This modules exports
Module objects
- class logging_strict.tech_niques.ClassAttribTypes(enum.Enum)¶
- As understood by :py:obj:`inspect.classify_class_attrs`
- class logging_strict.tech_niques.CaptureOutput¶
Context manager to capture both
sys.stdoutandsys.stderrstreams- __slots__: tuple[str, str, str, str] = ("_stdout_output", "_stderr_output", "_stdout", "_stderr")¶
Reduce class memory footprint
- _stderr¶
- _stderr_output¶
- _stdout¶
- _stdout_output¶
- class logging_strict.tech_niques.FuncWrapper(func)¶
Wraps 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:
- class logging_strict.tech_niques.LoggerRedirector¶
unittestredirectssys.stdoutandsys.stderr. Keep a reference to the real streams so we can later be reverted. Logging goes to the wrong IO streams. Upon failure, there are no log messages.Redirect to the correct IO streams.
Required for the unittest discover command:
--bufferoption- _real_stdout
Hold
sys.stdoutreference. Restores sys.stdout at the end of the context manager
- _real_stderr
Hold
sys.stderrreference. Restores sys.stdout at the end of the context manager
Usage
In a unittest module (level), setup
logging.basicConfig>>> import sys >>> import logging >>> logging.basicConfig( ... format='%(module)s %(levelname)s: %(message)s', ... level=logging.INFO, ... stream=sys.stdout, ... )
In a unittest module class
import sys import logging from logging_strict.tech_niques import LoggerRedirector def setUp(self): # unittest has reassigned sys.stdout and sys.stderr by this point g_module = f"[app_name].tests.test_[module name]" self._LOGGER = logging.getLogger(g_module) # %(asctime)s logging.basicConfig( format="%(levelname)s %(module)s: %(message)s", level=logging.INFO, stream=sys.stdout, ) LoggerRedirector.redirect_loggers( fake_stdout=sys.stdout, fake_stderr=sys.stderr, ) def tearDown(self): # unittest will revert sys.stdout and sys.stderr after this LoggerRedirector.reset_loggers( fake_stdout=sys.stdout, fake_stderr=sys.stderr, )
See also
In unittests, showing log messages on failure
- _real_stderr = <_io.TextIOWrapper name='<stderr>' mode='w' encoding='utf-8'>¶
- _real_stdout = <_io.TextIOWrapper name='<stdout>' mode='w' encoding='utf-8'>¶
- static all_loggers()¶
Get loggers
- Returns:
space separated tests (method name(s))
- Return type:
Sequence[logging.Logger]
- classmethod redirect_loggers(fake_stdout=None, fake_stderr=None) None¶
unittest temporarily switch the IO streams. Use the unittest temporary IO streams
Call in unittest class setUp method
- logging_strict.tech_niques.captureLogs(logger=None, level=None, format_='%(levelname)s %(module)s %(funcName)s: %(lineno)d: %(message)s')¶
A context manager to capture logging a loggers logging output
Example:
import logging from logging_strict.tech_niques import captureLogs with captureLogs('foo', level='INFO') as cm: logging.getLogger('foo').info('first message') logging.getLogger('foo.bar').error('second message') print(cm.output)
The watcher (
logging_strict.tech_niques.logging_capture._LoggingWatcher) has attributes:output
records
unformatted records
- Parameters:
- Returns:
Context manager yields one
logging_strict.tech_niques.logging_capture._LoggingWatcher. Which stores the log records/messages- Return type:
Iterator[logging_strict.tech_niques.logging_capture._LoggingWatcher]
See also
Context manager howto, PEP 343
- logging_strict.tech_niques.detect_coverage() bool¶
Running by coverage and running by unittest behavior differs!
- Returns:
Trueif runner is coverage otherwiseFalse- Return type:
See also
Todo
why coverage overrides logging.config?
When run by coverage, logging level becomes logging.INFO When run by unittest, logging level is same as logging.config
How to get the same behavior
- logging_strict.tech_niques.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.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]]
- logging_strict.tech_niques.is_class_attrib_kind(cls, str_m, kind)¶
For testing an ABC implementation
- Parameters:
- Returns:
Trueif is expectedlogging_strict.tech_niques.is_class_attrib_kind.params.kindotherwiseFalse- Return type:
- Raises:
TypeError– Expecting a strAssertionError– Expecting a class