Implementing a plug-in mechanism

Thomas Passin list1 at tompassin.net
Wed Mar 15 15:42:10 EDT 2023


On 3/15/2023 2:45 PM, dn via Python-list wrote:
> On 16/03/2023 01.47, Loris Bennett wrote:
>> I have written a program which, as part of the non-core functionality,
>> contains a module to generate email.  This is currently very specific
>> to my organisation, so the main program contains
>>
>>    import myorg.mailer
>>
>> This module is specific to my organisation in that it can ask an
>> internal server to generate individualised salutations for a given UID
>> which is known within the organisation.
>>
>> I want to share the code with other institutions, so I would like to
>>
>>    1. replace the organisation-specific mailer with a generic one
>>    2. allow an organisation-specific mailer to be used instead of the
>>       generic one, if so desired
> 
> This may call for the plug-in pattern, ie the user will choose whether 
> to plug-in the specific, or the generic, module.
> 
> In Python, we would tend to use a Dependency Injection approach (one of 
> Uncle Bob's SOLID principles).
[snip]

Here is (slightly modified) plugin code I'm using in one project.  You 
could use a naming convention to see if there is a plugin for a specific 
organizations, or each module could contain a UID variable which you 
could inspect to find the desired one.  This code is under the MIT 
License, so feel free to adapt it if you like.

def import_all_plugins(plugins_import_list, plugin_dir):
     """Import modules from the plugins directory and return a list of them.

     If plugins_import_list is not empty or None, only import the ones
     listed there. Otherwise import all ".py" files.

     RETURNS
     a list of successfully imported modules.
     """
     modules = []

     if not plugins_import_list:
         plugins_import_list = []
         for root, dirs, files in os.walk(plugin_dir):
             if root == plugin_dir:
                 break
         for f in files:
             f, ext = os.path.splitext(f)
             if ext == '.py':
                 plugins_import_list.append(f)

     for f in plugins_import_list:
         try:
             mod = importlib.import_module(f'plugins.{f}')
             modules.append(mod)
         except ImportError as e:
             print(f'{__name__}: {f} plugin: {e}')
             continue
     return modules




More information about the Python-list mailing list