classification
Title: Given a module hierarchy string 'a.b.c', add an easy way to import tail module 'c'
Type: enhancement Stage:
Components: Library (Lib) Versions: Python 3.1, Python 2.7
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: georg.brandl, mrts
Priority: normal Keywords: patch

Created on 2008-11-26 11:58 by mrts, last changed 2009-04-01 18:46 by georg.brandl. This issue is now closed.

Files
File name Uploaded Description Edit
issue4438.diff mrts, 2008-11-26 14:23 Add 'submodule' argument to __import__()
imp_import_module.diff mrts, 2008-11-28 19:01
Messages (8)
msg76460 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-26 11:58
The need to dynamically import module foo given a module name string
'bar.baz.foo' is quite common.

Quite often, the hack described in http://bugs.python.org/issue2090 is
used (see e.g. the Google code results linked from the issue).

Quoting Brett Cannon from the issue:
"I plan to add a much simpler API to the imp module for people to use
directly so that these abuses don't continue."

Although there are reasonable workarounds, let the current ticket be a
remainder for Brett that his plan is indeed needed.

Perhaps the easiest thing to do would be to add yet another argument,
e.g. 'toplevel', to __import__, such that:

>>> __import__('imprt.foo.foo') # toplevel=True by default
<module 'imprt' from 'imprt/__init__.pyc'>
>>> __import__('imprt.foo.foo', toplevel=False)
<module 'imprt.foo.foo' from 'imprt/foo/foo.pyc'>

The latter can currently be achieved by

>>> __import__('imprt.foo.foo', {}, {}, ['foo'])
<module 'imprt.foo.foo' from 'imprt/foo/foo.pyc'>

which is cumbersome if the module name is given in a string, resulting
in unnecessarily complex code:

modname = "imprt.foo.foo"
>>> __import__(modname, {}, {}, [modname.rsplit(".", 1)[-1]])
<module 'imprt.foo.foo' from 'imprt/foo/foo.pyc'>
msg76466 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-26 14:23
Attached is a naive proof-of-concept implementation (that breaks things,
i.e. the real implementation should strive for better
general compatibility), but works as expected:

>>> __import__('imprt.foo.foo', submodule=True)
<module 'imprt.foo.foo' from 'imprt/foo/foo.py'>

>>> __import__('imprt.foo.foo', submodule=False)   
<module 'imprt' from 'imprt/__init__.py'>

>>> __import__('imprt.foo.foo')
<module 'imprt' from 'imprt/__init__.py'>

# Die on unexpected arguments like strings, lists etc to
# avoid confusion
>>> __import__('imprt.foo.foo', submodule='z')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: an integer is required
msg76468 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-26 15:15
Just a note that `make test` passes:

322 tests OK.
38 tests skipped:
    test_aepack test_al test_applesingle test_bsddb test_bsddb185
    test_bsddb3 test_cd test_cl test_codecmaps_cn test_codecmaps_hk
    test_codecmaps_jp test_codecmaps_kr test_codecmaps_tw test_curses
    test_dbm test_dl test_gl test_imageop test_imgfile test_kqueue
    test_linuxaudiodev test_macos test_macostools test_normalization
    test_ossaudiodev test_pep277 test_py3kwarn test_scriptpackages
    test_socketserver test_startfile test_sunaudiodev test_tcl
    test_timeout test_urllib2net test_urllibnet test_winreg
    test_winsound test_zipfile64
3 skips unexpected on linux2:
    test_tcl test_dbm test_bsddb
msg76497 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-27 12:53
Corrections and clarifications:

 * I'd say labeling the patch naive and "breaking things" was misleading
(there was a breakage that resulted from stale files with incorrect
permissions from my previous build of Python 2.6; after a make distclean
all tests passed as described above). The patch is correct and
backwards-compatible in Python level, but it introduces a change in the
C API:

 PyAPI_FUNC(PyObject *) PyImport_ImportModuleLevel(char *name,
-       PyObject *globals, PyObject *locals, PyObject *fromlist, int level);
+       PyObject *globals, PyObject *locals, PyObject *fromlist,
+       int level, char submodule);


 * The patch was made against Python 2.6 release source.

 * The argument is named 'submodule' instead of 'toplevel' to avoid
confusion with 'level'.
msg76515 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-27 20:49
See also
http://mail.python.org/pipermail/python-dev/2008-November/083727.html
msg76549 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-28 18:59
Implement imp.import_module() instead. See
http://mail.python.org/pipermail/python-dev/2008-November/083758.html
msg76550 - (view) Author: Mart Sõmermaa (mrts) Date: 2008-11-28 19:05
Note that the hack described in http://bugs.python.org/issue2090 should
be disabled once this gets integrated.
msg85071 - (view) Author: Georg Brandl (georg.brandl) * (Python committer) Date: 2009-04-01 18:46
This feature is implemented as importlib.import_modules() in 2.7 and
3.1; for earlier versions there is also a backport on PyPI.
History
Date User Action Args
2009-04-01 18:46:48georg.brandlsetstatus: open -> closed

nosy: + georg.brandl
messages: + msg85071

resolution: out of date
2008-11-28 19:09:09mrtssetcomponents: - Interpreter Core
title: Add an easy way to __import___ submodules -> Given a module hierarchy string 'a.b.c', add an easy way to import tail module 'c'
2008-11-28 19:05:43mrtssetmessages: + msg76550
2008-11-28 19:02:09mrtssetfiles: + imp_import_module.diff
messages: + msg76549
2008-11-27 20:49:07mrtssetmessages: + msg76515
2008-11-27 12:53:31mrtssetmessages: + msg76497
2008-11-26 15:15:53mrtssetmessages: + msg76468
2008-11-26 14:23:58mrtssetfiles: + issue4438.diff
keywords: + patch
messages: + msg76466
2008-11-26 11:58:38mrtscreate