Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most Pythonic way to provide function metadata at compile time?

I am building a very basic platform in the form of a Python 2.7 module. This module has a read-eval-print loop where entered user commands are mapped to function calls. Since I am trying to make it easy to build plugin modules for my platform, the function calls will be from my Main module to an arbitrary plugin module. I'd like a plugin builder to be able to specify the command that he wants to trigger his function, so I've been looking for a Pythonic way to remotely enter a mapping in the command->function dict in the Main module from the plugin module.

I've looked at several things:

  1. Method name parsing: the Main module would import the plugin module and scan it for method names that match a certain format. For example, it might add the download_file_command(file) method to its dict as "download file" -> download_file_command. However, getting a concise, easy-to-type command name (say, "dl") requires that the function's name also be short, which isn't good for code readability. It also requires the plugin developer to conform to a precise naming format.

  2. Cross-module decorators: decorators would let the plugin developer name his function whatever he wants and simply add something like @Main.register("dl"), but they would necessarily require that I both modify another module's namespace and keep global state in the Main module. I understand this is very bad.

  3. Same-module decorators: using the same logic as above, I could add a decorator that adds the function's name to some command name->function mapping local to the plugin module and retrieve the mapping to the Main module with an API call. This requires that certain methods always be present or inherited though, and - if my understanding of decorators is correct - the function will only register itself the first time it is run and will unnecessarily re-register itself every subsequent time thereafter.

Thus, what I really need is a Pythonic way to annotate a function with the command name that should trigger it, and that way can't be the function's name. I need to be able to extract the command name->function mapping when I import the module, and any less work on the plugin developer's side is a big plus.

Thanks for the help, and my apologies if there are any flaws in my Python understanding; I'm relatively new to the language.

like image 235
mieubrisse Avatar asked Feb 12 '13 09:02

mieubrisse


People also ask

What is __ module __ in Python?

The __module__ property is intended for retrieving the module where the function was defined, either to read the source code or sometimes to re-import it in a script.

How do you define a function in Python?

Basic Syntax for Defining a Function in Python In Python, you define a function with the def keyword, then write the function identifier (name) followed by parentheses and a colon. The next thing you have to do is make sure you indent with a tab or 4 spaces, and then specify what you want the function to do for you.


1 Answers

Building or Standing on the first part of @ericstalbot's answer, you might find it convenient to use a decorator like the following.

################################################################################
import functools
def register(command_name):
    def wrapped(fn):
        @functools.wraps(fn)
        def wrapped_f(*args, **kwargs):
            return fn(*args, **kwargs)
        wrapped_f.__doc__ += "(command=%s)" % command_name
        wrapped_f.command_name = command_name
        return wrapped_f
    return wrapped
################################################################################
@register('cp')
def copy_all_the_files(*args, **kwargs):
    """Copy many files."""
    print "copy_all_the_files:", args, kwargs
################################################################################

print  "Command Name: ", copy_all_the_files.command_name
print  "Docstring   : ", copy_all_the_files.__doc__

copy_all_the_files("a", "b", keep=True)

Output when run:

Command Name:  cp
Docstring   :  Copy many files.(command=cp)
copy_all_the_files: ('a', 'b') {'keep': True}
like image 153
sotapme Avatar answered Sep 25 '22 14:09

sotapme