Ben
Ben

Reputation: 1295

How to create a python decorator programatically

I am writing an app that creates/provides various Python decorators. I'd like this app to be localized, including the names of the decorators. The decorators would ultimately be used by other developers who are using my app as a framework (think of my app as a test framework).

Ideally, I'd like to have the ability to create the decorators dynamically based on the localization settings.

For instance, if the language selected is English, I'd like my decorator to be named "apple", and if it's French, I'd like it to be named "pomme".

In the Python code, it would either look like:

@apple
def my_func():
    pass

or

@pomme
def my_func():
    pass

I ultimately want to have the flexibility to add many more languages without having to modify or duplicate a bunch of code. Ideally, I would only have one decorator function that would handle "apple" or "pomme" depending on the settings.

What's the best way to achieve this?

Upvotes: 0

Views: 371

Answers (1)

Suor
Suor

Reputation: 3055

First, don't do this. This will bring many problems upon you and make life much harder for you and your users. Anyway, python is very dynamic so you can do that.

Setup your package like that:

yourpackage/
    __init__.py
    decorators.py

In decorators.py:

# List all decorators you want to publish. Use english names here.
__all__ = ['apple', 'orange', ...]

# Here come implementations named in english
def apple(...):
    ...

...

In __init__.py:

# Whatever over submodules export or just []
__all__ = [...]

from . import decorators

# Get locale somehow
LOCALE = ...

# This translation function could be as complex as you wish
# I use a lookup in hard-coded dict
TRANSLATIONS = {
    'fr': {'apple': u'pomme', ...},
    ...
}
def _translate_name(name):
    # If something is not translated we use default english name,
    # could be easily changed to raise error
    return TRANSLATIONS.get(LOCALE, {}).get(name, name)

# Generate dynamic attributes to current module and add them to __all__
import sys
this_module = sys.modules[__name__]

for name in decorators.__all__:
    translated = _translate_name(name)
    setattr(this_module, translated, getattr(decorators, name))
    __all__.append(translated)

Managing __all__ in __init__.py is optional. This is to allow from yourmodule import *.

Upvotes: 1

Related Questions