user3200309
user3200309

Reputation: 21

How to structure a Python package so others can add modules easily

I have a component-oriented Python (3.3) project. I have a base Component class. I want others to be able to add modules that contain subclasses of Component just by copying their .py file(s) into some folder, without having to edit anything. Running the main program should then simply import all the .py files found in that folder. All accesses from my main program to these subclasses are via Component.__subclasses__(), not by explicit name. I am not especially worried about name clashes between code in different user-written modules, but of course I would like to avoid it if possible without screwing up the simple drop-file-into-folder inclusion.

How do I structure a package to achieve this?

Upvotes: 2

Views: 114

Answers (1)

User
User

Reputation: 14883

I would structure the package like this:

myPackage
+ -- __init__.py
+ -- Component.py
+ -- user_defined_packages
     + -- __init__.py # 1
     + -- example.py

Ideas:

  1. let the users drop into a different folder so that they do not mix up your code and theirs
  2. The init file in user_defined_packages can load all the subpackages once user_defined_packages is imported. It must print all errors.

__init__.py # 1

import os
import traceback
import sys

def import_submodules():
    def import_submodule(name):
        module_name = __name__ + '.' + name
        try:
            __import__(module_name)
        except:
            traceback.print_exc() # no error should pass silently
        else:
            module = sys.modules[module_name]
            globals()[name] = module # easier access

    directory = os.path.dirname(__file__)
    for path_name in os.listdir(directory):
        path = os.path.join(directory, path_name)
        if path_name.startswith('_'):
            # __pycache__, __init__.py and others
            continue
        if os.path.isdir(path):
            import_submodule(path_name)
        if os.path.isfile(path):
            name, extension = os.path.splitext(path_name)
            if extension in ('.py', '.pyw'):
                import_submodule(name)

import_submodules()

Upvotes: 2

Related Questions