Recently, you have to work quite a bit with Python. Solving one of the current tasks, it became necessary within the function decorator to check whether the decorated method was decoded by another decorator. Unfortunately, the standard means of reflection of the language do not allow it. More precisely, using, for example, the inspect module from the standard library can do this, but it really didn’t like this approach.
Under the cut is your own method for solving a problem that has resulted in a small library available for general use.
So, it was decided to create and use some special register of decorators. Those. register any decorator function in this registry before using it as a decorator. After that, using the registry API, you can simply track the use of registered decorators on methods, functions and modules.
Nevertheless, there are a few rules to remember. Registering built-in decorators will not work. That is, unfortunately, it is impossible to track decorators such as
@staticmethod
,
@classmethod
and the like (if someone can find a solution to this problem, I will be very grateful). And most importantly, decorators must be registered
before they are used .
')
In fact, the mechanics of the registry is quite simple. By registering a decorator, you actually get a decorated source decorator which, in addition to its original functionality, also records information about itself in the attribute "__annotations__" of the function being decorated.
If a function (or method) is decorated by several decorators, it is important only to register all decorators before using them and all decorators will be correctly taken into account. Ie, the construction of the form:
@decorator_one @decorator_two @decorator_three def some_function(): pass
will work successfully.
The library “regd” (as I called it) is compatible with both Python 2.x and version 3.x (we use both branches on our projects, so compatibility has been tested).
The source code is available on
Github , the license, as always - MIT, so do whatever you want.
Documentation is
here .
You can install it just through PyPI:
$ pip install regd
Below are a few words about the functionality.
1. Registration decorators.
“Ordinary” and “parameterized” decorators should be registered using different methods:
from regd import DecoratorRegistry as dreg
2. Reflection API
To make the API functions more understandable, let's first create and register a simple decorator, which in fact does nothing, but simply exists.
from regd import DecoratorRegistry as dreg # def mydecorator( fn) : # - ... def wrapper( *args, **kwargs) # ... - ... return fn( *args, **kwargs) return wrapper # mydecorator = dreg.decorator( mydecorator)
Remember - register decorators need
to use them .
Now, after registering, we can use our decorator as usual:
@mydecorator def myfunc() : pass
Now, at any time from any place in the code, we can find out whether the function has been decorated by the decorator:
print( dreg.is_decorated_with( myfunc, mydecorator))
Some more useful methods:
all_decorated_module_functions( module, exclude_methods=False, exclude_functions=False)
- allows you to get all the functions and / or class methods decorated by registered decorators in a given modulemodule_functions_decorated_with( module, decorator, exclude_methods=False, exclude_functions=False)
- allows you to get all the functions and / or class methods decoded by a given decorator in a given moduledecorated_methods( cls, decorator)
- we get all the methods of a class / object decorated with a given decoratorget_decorators( fn)
- returns a list of all known decorators for the given function / methodget_real_function( fn)
- returns the reference to the original function, which was decoded by the decorators (yes, you can get access to the original function and even perform it to bypass the decoration)is_decorated_with( fn, decorator)
- checks if the given function is is_decorated_with( fn, decorator)
by the specified decorator
I hope someone will come in handy or seem useful. All comments and suggestions are welcome.