2

@wrapt conditional monkey patching with decorators

Wrapt has two feature

  • best practice for decorators
  • monkey patching

I'm doing both to be able to conditionally change method called. I've provided an example which is based on pandas version. While this works, I have resorted to barebones monkey patching and not using wrapt capability. How can wrapt be used to monkey patch the alternate method?

import pandas as pd
import wrapt, inspect
from distutils.version import StrictVersion
def alt_impl(alt_fn, cond):
    @wrapt.decorator
    def wrapper(wrapped, instance, args, kwargs):
        nonlocal alt_fn
        if cond():
            # @staticmethod and @classmethod need to navigate to actual function
            if not inspect.isfunction(alt_fn):
                alt_fn = alt_fn.__func__
            # class instance methods need to be bound to class instance
            if instance is not None:
                alt_fn = alt_fn.__get__(instance, instance.__class__)
            return alt_fn(*args, **kwargs)
        else:
            return wrapped(*args, **kwargs)
    return wrapper

Example usage

class alt_impl_example():
    def upgraded_pandas(self, args):
        print(f"upgraded {pd.__version__}") 

    @alt_impl(upgraded_pandas, lambda: StrictVersion(pd.__version__) >= StrictVersion("1.0.0")) 
    def pandas(self, args): 
        print(pd.__version__) 

t = alt_impl_example()
t.pandas({})
Rob Raymond
  • 29,118
  • 3
  • 14
  • 30
  • Why not use the ``enabled`` option to ``@wrapt.decorator``. It provides support for conditional application of decorators at time of import, rather than at time of execution, which would seem to satisfy your requirement. See https://wrapt.readthedocs.io/en/latest/decorators.html#enabling-disabling-decorators – Graham Dumpleton Mar 14 '20 at 23:44

0 Answers0