Documentation
Hey there.
importlib.__import__ does’t seem to have much documentation, but AFAIU it’s intended to be identical to the build-in __import__, for which the documentation says:
When the name variable is of the form package.module, normally, the top-level package (the name up till the first dot) is returned, not the module named by name. However, when a non-empty fromlist argument is given, the module named by name is returned.
While this is strictly speaking true, assuming that the package.module really implies its for absolute modules only, it may be ambiguous, because AFAIU it's not as described for relative modules:
If we look at:
|
if level == 0: |
|
module = _gcd_import(name) |
|
else: |
|
globals_ = globals if globals is not None else {} |
|
package = _calc___package__(globals_) |
|
module = _gcd_import(name, package, level) |
|
if not fromlist: |
|
# Return up to the first dot in 'name'. This is complicated by the fact |
|
# that 'name' may be relative. |
|
if level == 0: |
|
return _gcd_import(name.partition('.')[0]) |
|
elif not name: |
|
return module |
|
else: |
|
# Figure out where to slice the module's name up to the first dot |
|
# in 'name'. |
|
cut_off = len(name) - len(name.partition('.')[0]) |
|
# Slice end needs to be positive to alleviate need to special-case |
|
# when ``'.' not in name``. |
|
return sys.modules[module.__name__[:len(module.__name__)-cut_off]] |
Then at the beginning module is whatever _gcd_import returned, which is AFAIU always the "rightmost" module, that is in foo.bar it would be bar and in ., .. or ..baz it would be the rightmost oft whatever these resolve to given the respective package.
Then in case there is no fromlist, we have that if.
if level == 0, i.e. module is absolute, so it returns _gcd_import(name.partition('.')[0]), i.e. the left-most / top-level module. (btw: why does it re-import and not just take it from `sys.modules like it's down in the 3rd case??)
elif not name:, i.e. when name is empty, which it would be if the module to be imported is dots only like ., .. (but not .foo).
Now here the behaviour seems to differ compared to absolute modules... we really get the current module i.e. the rightmost one (which is not the top-level)
else:, this is for the cases of relative modules that are not only dots, so .foo, ..bar etc.. Here it again returns the top level module (but this time, simply taking it from sys.modules (unlike above where it seemed to "re-import" the top-level.
So we have now two different behaviour for relative modules, which also differs from what might be taken as general rule of thumb ("no fromlist => top level") from the docs.
I think it might be worth to explain that a bit more.
Oh and what might also make sense to document is, that name can be empty (if level >0) and what that means (i.e. ., .., etc.)...
Cheers,
Chris.
Documentation
Hey there.
importlib.__import__does’t seem to have much documentation, but AFAIU it’s intended to be identical to the build-in__import__, for which the documentation says:While this is strictly speaking true, assuming that the
package.modulereally implies its for absolute modules only, it may be ambiguous, because AFAIU it's not as described for relative modules:If we look at:
cpython/Lib/importlib/_bootstrap.py
Lines 1395 to 1414 in f6ed7c0
Then at the beginning
moduleis whatever_gcd_importreturned, which is AFAIU always the "rightmost" module, that is infoo.barit would bebarand in.,..or..bazit would be the rightmost oft whatever these resolve to given the respective package.Then in case there is no
fromlist, we have thatif.if level == 0, i.e. module is absolute, so it returns_gcd_import(name.partition('.')[0]), i.e. the left-most / top-level module. (btw: why does it re-import and not just take it from `sys.modules like it's down in the 3rd case??)elif not name:, i.e. whennameis empty, which it would be if the module to be imported is dots only like.,..(but not.foo).Now here the behaviour seems to differ compared to absolute modules... we really get the current
modulei.e. the rightmost one (which is not the top-level)else:, this is for the cases of relative modules that are not only dots, so.foo,..baretc.. Here it again returns the top level module (but this time, simply taking it fromsys.modules(unlike above where it seemed to "re-import" the top-level.So we have now two different behaviour for relative modules, which also differs from what might be taken as general rule of thumb ("no fromlist => top level") from the docs.
I think it might be worth to explain that a bit more.
Oh and what might also make sense to document is, that
namecan be empty (iflevel>0) and what that means (i.e..,.., etc.)...Cheers,
Chris.