hbutils.testing.isolated

Overview:

Utilities for isolating environment, which can be using in testing.

isolated_directory

hbutils.testing.isolated.isolated_directory(mapping: Optional[Dict[str, str]] = None) → AbstractContextManager[source]
Overview:

Do something in an isolated directory.

Parameters:

mapping – Mappings for the isolated directory.

Examples::
  • Simple usage

>>> import os
>>> import pathlib
>>> from hbutils.testing import isolated_directory
>>>
>>> with isolated_directory():
...     with open('file.txt', 'w') as f:
...         print("Line 1", file=f)
...         print("Line 2rd", file=f)
...     print(os.listdir('.'))
...     print(pathlib.Path('file.txt').read_text())
['file.txt']
Line 1
Line 2rd
>>> print(os.listdir('.'))
['hbutils', 'README.md', 'requirements.txt', ...]
  • Mapping files and directory inside

>>> import os
>>> from hbutils.testing import isolated_directory
>>>
>>> with isolated_directory({
...     'ts': 'hbutils/testing',
...     'README.md': 'README.md',
... }):
...     print(os.listdir('.'))
...     print(os.listdir('ts'))
['README.md', 'ts']
['capture', 'generator', 'isolated', '__init__.py']

isolated_stdin

hbutils.testing.isolated.isolated_stdin(v: Union[str, List[str]], mem: bool = False)[source]
Overview:

Isolation for stdin stream.

Parameters:
  • v – Input content, a whole string or a list of string supported.

  • mem – Use memory or not. Default is False which means a temporary file will be used as fake input stream.

Examples::
>>> from hbutils.testing import isolated_stdin
>>> with isolated_stdin(['123', '456']):
...     a = int(input())
...     b = int(input())
...     print(a, b, a + b)
123 456 579

isolated_entry_points

hbutils.testing.isolated.isolated_entry_points(group: str, fakes: Optional[Union[List, Dict[str, Any]]] = None, auto_import: bool = True, clear: bool = False)[source]
Overview:

Isolation for pkg_resources.iter_entry_points() function. Can be used to fake the plugins, or just disable the installed plugins.

importlib.metadata and importlib_metadata are supported now.

Parameters:
  • group – Group name.

  • fakes – Fake entry points. Dict or list are accepted.

  • auto_import – Auto import the object from string. Default is True which means if a string is given, dynamic import will be performed.

  • clear – Clear the original entry points or not. Default is False which means the original entry points will be kept and be able to be iterated.

Examples::
>>> import importlib.metadata
>>> import importlib_metadata  # backport for py3.7
>>> import pkg_resources  # deprecated
>>>
>>> from hbutils.testing import isolated_entry_points
>>>
>>> # nothing at the beginning
>>> print({ep.name: ep.load() for ep in
...        pkg_resources.iter_entry_points('my_plugin')})
{}
>>> print(importlib.metadata.entry_points().get('my_plugin', None))
None
>>> print(importlib_metadata.entry_points(group='my_plugin'))
()
>>>
>>> # mock the plugins
>>> with isolated_entry_points('my_plugin', [
...     (
...             'quick_import_object',  # name import
...             'hbutils.reflection.quick_import_object'
...     ),
...     ('func_filter', filter),  # named entry object
...     map,  # simple function
...     'hbutils.system.is_binary_file',  # simple import
... ]):
...     print({ep.name: ep.load() for ep in
...            pkg_resources.iter_entry_points('my_plugin')})
...     print(importlib.metadata.entry_points()['my_plugin'])
...     print(importlib_metadata.entry_points(group='my_plugin'))
...
{'quick_import_object': <function quick_import_object at 0x7f6d0dd5ad40>, 'func_filter': <class 'filter'>, 'map': <class 'map'>, 'is_binary_file': <function is_binary_file at 0x7f6d0dcd8550>}
[_FakeEntryPoint(name='quick_import_object', group='my_plugin', dist=<function quick_import_object at 0x7f6d0dd5ad40>), _FakeEntryPoint(name='func_filter', group='my_plugin', dist=<class 'filter'>), _Fak
eEntryPoint(name='map', group='my_plugin', dist=<class 'map'>), _FakeEntryPoint(name='is_binary_file', group='my_plugin', dist=<function is_binary_file at 0x7f6d0dcd8550>)]
[_FakeEntryPoint(name='quick_import_object', group='my_plugin', dist=<function quick_import_object at 0x7f6d0dd5ad40>), _FakeEntryPoint(name='func_filter', group='my_plugin', dist=<class 'filter'>), _Fak
eEntryPoint(name='map', group='my_plugin', dist=<class 'map'>), _FakeEntryPoint(name='is_binary_file', group='my_plugin', dist=<function is_binary_file at 0x7f6d0dcd8550>)]
>>> with isolated_entry_points('my_plugin', {
...     'func_map': map,
...     'func_binary': 'hbutils.system.is_binary_file'
... }):
...     print({ep.name: ep.load() for ep in
...            pkg_resources.iter_entry_points('my_plugin')})
...     print(importlib.metadata.entry_points()['my_plugin'])
...     print(importlib_metadata.entry_points(group='my_plugin'))
...
{'func_map': <class 'map'>, 'func_binary': <function is_binary_file at 0x7f6d0dcd8550>}
[_FakeEntryPoint(name='func_map', group='my_plugin', dist=<class 'map'>), _FakeEntryPoint(name='func_binary', group='my_plugin', dist=<function is_binary_file at 0x7f6d0dcd8550>)]
[_FakeEntryPoint(name='func_map', group='my_plugin', dist=<class 'map'>), _FakeEntryPoint(name='func_binary', group='my_plugin', dist=<function is_binary_file at 0x7f6d0dcd8550>)]
>>> # nothing at the ending
>>> print({ep.name: ep.load() for ep in
...        pkg_resources.iter_entry_points('my_plugin')})
{}
>>> print(importlib.metadata.entry_points().get('my_plugin', None))
None
>>> print(importlib_metadata.entry_points(group='my_plugin'))
()

Warning

The pkg_resources package is no longer officially supported. However, certain libraries that rely on hbutils are still in use, hence temporary support will be provided. The official guidance must be followed to migrate to importlib.metadata at the earliest opportunity. In addition, support for the pkg_resources package in this function will be discontinued in the next major version.

isolated_logger

hbutils.testing.isolated.isolated_logger(logger: Optional[Union[str, logging.Logger]] = None, handlers: Optional[List[logging.Handler]] = None, close_handlers: bool = True)[source]
Overview:

Mock loggers in logging module.

Parameters:
  • logger – Logger or logger’s name for isolation.

  • handlers – Initial handlers for isolation.

  • close_handlers – Close handler’s after complete.

Examples::
>>> import logging
>>> from rich.logging import RichHandler  # a 3rd-party logger
>>> from hbutils.testing import isolated_logger
>>>
>>> logging.error('this is error')  # normal log
ERROR:root:this is error
>>> logging.error('this is error')
ERROR:root:this is error
>>> with isolated_logger(handlers=[  # replaced with custom handlers
...     RichHandler(),
...     logging.FileHandler('test_log.txt'),
... ]):
...     logging.error('this is error inside 1')
...     logging.error('this is error inside 2')
[11/08/22 15:39:37] ERROR    this is error inside 1                    <stdin>:5
                    ERROR    this is error inside 2                    <stdin>:6
>>> logging.error('this is error')  # change back to normal log
ERROR:root:this is error
>>> logging.error('this is error')
ERROR:root:this is error