fahadh4ilyas
fahadh4ilyas

Reputation: 480

How to Call All Modules inside Package?

I have a project which has this hierarchy

tasker/
        table/
                __init__.py
                user.py
                task.py
                ...
        __init__.py
        tasker.py

every file inside table folder (except __init__.py) contains a class that has a same name as the file name except the first letter is capitalized. I want to call and instantiate every class inside table folder in tasker.py. I can do it by writing

import table

inside tasker.py. But, it turns out that I have to write for example

table.user.User()

to instantiate class inside user.py and it looks very ugly. Is there any way so that I only type at least

user.User()

or even better,

User()

to instantiate those classes?

Note: Every files inside table folder is dinamically changed. I might add or remove file in table folder.

Upvotes: 0

Views: 432

Answers (3)

Mad Physicist
Mad Physicist

Reputation: 114478

I would suggest doing most of the work automatically. You can register your modules of interest in tasker.table.__init__:

table_registry = ['user', 'task', ...]

You don't need to import anything at this point and I wouldn't recommend using __all__ as it serves a different purpose altogether. The advantage of using a manually created list is that your package can contain other modules without any interference.

Now tasker.tasker can do all the work dynamically:

from .table import table_registry
from importlib import import_module

pkg = 'tasker.table'
for name in table_registry:
    mod = import_module('.' + name, package=pkg)
    name = name.titlecase()
    # Check if module contains uppercased class name
    if hasattr(mod, name):
        cls = getattr(mod, name)
        # Check if it's a class
        if isinstance(cls, type):
            # Assign to current module
            globals()[name] = cls

del name, mod, cls

If you don't want to bother with manually registering your modules of interest, you can dynamically discover them using the utilities in pkgutil. In This version, tasker.table.__init__ can remain empty. tasker.tasker will get the module list like this:

from pkgutil import walk_packages
from importlib import import_module

for info in walk_packages(tasker.table.__path__, prefix='tasker.table.'):
    if info.ispkg: continue
    mod = import_module(info.name)
    name = info.name.split('.')[-1].titlecase()
    if hasattr(mod, name):
        ...

The remainder of the code is the same as for the manual version. This version will recurse into any sub-packages it finds. It will work fine as long as you don't do anything crazy with your __path__ attributes.

Upvotes: 2

sudonym
sudonym

Reputation: 4018

you can import all modules inside a package at once using asterisks:

from table import *

Upvotes: 0

Bhaskar
Bhaskar

Reputation: 1946

This might work

from table import user

user.User()

Upvotes: 0

Related Questions