Performing star imports with importlib inside module

I’m trying to do a star import inside a module with importlib so that the current module namespace gets populated in the same fashion.

# faz/boo.py
from faz._boo import *

What I’ve tried to do.

# faz/__init__.py
from faz.far import *
# faz/far.py
from .boo import *
import sys

faz = sys.modules[__name__]

def farmethod(f):
    print("Calling", f.__name__)
    def wrapper(*args, **kwargs):
        f(*args, **kwargs)
    return wrapper

@faz.farmethod
def inscrutable():
    pass
# faz/_boo.py
# Whatever
# faz/boo.py
import importlib

root = importlib.import_module(__package__) # faz is used later

_boo = importlib.import_module(f'._boo', __package__)

if hasattr(_boo, '__all__'):
    __all__ = _boo.__all__
else:
    __all__ = [name for name in dir(_boo)]

globals().update({name: getattr(_boo, name) for name in __all__})

But this results in exceptions like.

Traceback (most recent call last):
  File "<string>", line 1, in <module>
    import faz; print(faz.__version__)
    ^^^^^^^^^^
  File "path/to/faz/__init__.py", line 1, in <module>
    from faz.far import *
  File "path/to/faz/far.py", line 12, in <module>
    @faz.farmethod
    ^^^^^^^^^^^^^^
AttributeError: module 'faz.boo' has no attribute 'farmethod'

I can’t see what I’m doing wrong, because it did work with the topmost snippet. Perhaps if you know something I’d be glad to hear.

This is not enough code for us to figure out what is going on. All we can tell you is what the error message already tells you: faz.boo does not have a farmethod. Since you aren’t providing close to a complete example, I don’t know why you think it should be there.

You’d need to import anything in __all__ that isn’t already there. Something like (untested):

if hasattr(_boo, '__all__'):
    __all__ = _boo.__all__
    for name in __all__:
        if not hasattr(_boo, name):
            setattr(_boo, name, importlib.import_module("." + name, _boo.__package__))
else:
    __all__ = [name for name in dir(_boo)]
1 Like

I know what it happened, some part of the code was using sys.modules[__name__] to save a module and for some reason __name__ is set to baz._boo when I run that star import implementation. If I knew better I could’ve done the following I wouldn’t be malding at this.

if hasattr(_boo, '__all__'):
    __all__ = _boo.__all__
else:
    __all__ = [name for name in dir(_boo) if name != "__name__"]

Why __name__ became polluted? I don’t know, but at least I’ve managed to do something. If you have something in mind you may just say it.

Still no one knows why __name__ got changed in the other module? I’ll remain with my doubt but at least I’ll mark this as resolved.

Because you told it to:

__all__ = [name for name in dir(_boo)]

globals().update({name: getattr(_boo, name) for name in __all__})

This will copy all attributes that dir deems “interesting”, which includes __name__.

Note that the entire code you have shown reeks of poorly design solutions for nonexistence or self inflicted issues. But I also can’t really tell what you are trying to do and I am honestly not sure if I am willing to spend the time to understand it.

None of the code you have shown looks like it should be anywhere near production, but maybe you have very good reasons to use it.

1 Like

This still doesn’t explain why the __name__ of the other module is affected, unless the update method on globals affect every namespace involved, which would then mean that I haven’t done a wise choice.

My objective is to import everything from a native module which implements GUI functionality from a set of bindings (like GTK and Qt), but I wanted to do it with importlib. The other option would be to hardcode those names.

Ok, so I am still misunderstanding your code.

Please show the actual code you are running if you want more help [1]. Me guessing what you are doing is clearly not helping.

That is honestly probably true anyway - I still cannot imagine a good reason for why you are using importlib/sys.modules[__name__].


  1. No, not a partially censored version with foo and bar - the actual code or a recreation of it ↩︎