Recording decorators & Filter formats

There are two types of decorators, be aware to not mix these.

  • Decorators for modification of loaded libraries - These decorators are in online_replacing and modules_decorate_all_methods files.
    • Shortcut of decorators for some sets applicable to the whole class.
    • Class decorators - Apply replacements decorators to all methods.
    • Method decorators - Apply replacements decorators to the method.
  • Replacement decorators wokflow - These decorators are part of helpers subdirectory and objects file where is the base class with main implementation.
    • Decorators for functions what should be modified (basic unit for working with object storage)

Class decorators

There are shortcuts for decorating the whole class by decorators for tests methods. You can define also setup and teardown methods for cassette as callback methods:

  • cassette_setup(self, cassette) - Setup cassette before test execution. It is executed after self.setUp method of unittest.
  • cassette_teardown(self, cassette) - Tear down method for cassette after test execution. It is executed before self.tearDown method of unittest.

Generic usage

It applies selected decorator to all methods of class. Structure is:

  • class decorator - apply_decorator_to_all_methods - Applies argument to all test methods (test.*).
  • type of matching - replace_module_match - Decorates already loaded modules via modify of sys.modules
  • what will be decorated - math.sin - Which module method will be decorated.
  • decorated by - Simple.decorator_plain() - This is the decorator for selected method in module.
@apply_decorator_to_all_methods(
   replace_module_match(
       what="math.sin", decorate=Simple.decorator_plain()
   )
)

Shortcuts for selected modules

The most user-friendly way how to work with requre, but just some modules or their parts are handled by these (focused on usage requre in packit projects).

They are stored in requre/modules_decorate_all_methods.py file.

  • record_tempfile_module - Workaround random file names via tempfile module. It changes it to use predictable names.
  • record_git_module - The git module handling, it allows to restore remote git operations like fetch, push, pull.
  • record_requests_module - Store all remote operations via requests module, it changes requests.Session.send method, so it should be very generic.

Test methods decorators

These decorators apply a decorator to the test method.

class Test(unittest.TestCase):

   @replace_module_match(
       what="requests.sessions.Session.request",
       decorate=RequestResponseHandling.decorator(item_list=["method", "url"]),
   )
   def test(self):
       response = requests.get("http://example.com")
       self.assertIn("This domain is for use", response.text)

Filters for transparent mode

This filters are used for transparent mode as part of improved import system, also deprecated usage for normal tests. The file could look like:

from requre.import_system import UpgradeImportSystem
from requre.helpers.simple_object import Simple

FILTERS = UpgradeImportSystem().decorate("time.sleep", Simple.decorator_plain())

Customization rules

from requre import decorate
from requre.helpers.requests import RequestResponseHandling
decorate("Session.send", RequestResponseHandling.decorator_plain())

It says

  • What to replace
  • Which decorator/replacements to use for the method
  • What to replace: Session.send
    There is used "." syntax to deep dive into object/module model. In this example, it means in full sense decorate send method of Session class in requests module
  • Object to be used: RequestResponseHandling.decorator_plain()
    It is function/object/method to be applied as decorator for Session.send.

Filter object model

Replacements

There are two functions/methods that can be used
  • decorate
  • replace

Example with replace

with replace(what="tempfile.mktemp", replacement=lambda x: lambda: "/tmp/random"):
    import tempfile
    tmpfile = tempfile.mktemp()
    assert "/tmp/random" == tmpfile

Reverting

Requre supports reverting import system to previous state, when used with with statement

  • Without reverting
    Usage without reverting back
replace(what="tempfile.mktemp", replacement=lambda x: "/tmp/random")
import tempfile
tmpfile = tempfile.mktemp()
  • With reverting
    when used with statement import system is returned to previous state
with replace(what="tempfile.mktemp", replacement=lambda x: "/tmp/random"):
    import tempfile
    tmpfile = tempfile.mktemp()
    assert "/tmp/random" == tmpfile

Chaining of operations

with replace(what="tempfile.mktemp", replacement=lambda x: "/tmp/random").\
    decorate(what="tempfile.mkdtemp", replacement=lambda x: lambda: os.makedirs("/tmp/randomdir"))
):
    import tempfile
    tmpfile = tempfile.mktemp()
    tempdir = tempfile.mkdtemp()