Simpler Python -builtin import

When using -builtin, the two step C-extension module import is now
one step and the wrapped API is only available once and not in an underlying
module attribute like it is without -builtin. To understand this, consider a
module named 'example' (using: %module example). The C-extension is compiled into
a Python module called '_example' and a pure Python module provides the actual
API from the module called 'example'. It was previously possible to additionally
access the API from the module attribute 'example._example'. The latter was an
implementation detail and is no longer available. It shouldn't have been used, but
if necessary it can be resurrected using the moduleimport attribute described in the
Python chapter of the documentation. If both modules are provided in a Python
package, try:

  %module(moduleimport="from . import _example\nfrom ._example import *") example
or more generically:
  %module(moduleimport="from . import $module\nfrom .$module import *") example

and if both are provided as global modules, try:

  %module(moduleimport="import _example\nfrom _example import *") example
or more generically:
  %module(moduleimport="import $module\nfrom $module import *") example

The module import code shown will appear in the example.py file.
This commit is contained in:
William S Fulton 2018-11-28 23:36:13 +00:00
commit 6b5da094b2
2 changed files with 53 additions and 27 deletions

View file

@ -693,37 +693,38 @@ public:
mod_docstring = NULL;
}
/* Import the C-extension module. This should be a relative import,
* since the shadow module may also have been imported by a relative
* import, and there is thus no guarantee that the C-extension is on
* sys.path. Relative imports must be explicitly specified from 2.6.0
* onwards (implicit relative imports raised a DeprecationWarning in 2.6,
* and fail in 2.7 onwards).
*
* First determine the shadow wrappers package based on the __name__ it
* was given by the importer that loaded it. Then construct a name for
* the module based on the package name and the module name (we know the
* module name). Use importlib to try and load it. If an attempt to
* load the module with importlib fails with an ImportError then fallback
* and try and load just the module name from the global namespace.
*/
Printv(default_import_code, "def swig_import_helper():\n", NULL);
Printv(default_import_code, tab4, "import importlib\n", NULL);
Printv(default_import_code, tab4, "pkg = __package__ if __package__ else __name__.rpartition('.')[0]\n", NULL);
Printf(default_import_code, tab4 "mname = '.'.join((pkg, '%s')).lstrip('.')\n", module);
Printv(default_import_code, tab4, "try:\n", NULL);
Printv(default_import_code, tab8, "return importlib.import_module(mname)\n", NULL);
Printv(default_import_code, tab4, "except ImportError:\n", NULL);
Printf(default_import_code, tab8 "return importlib.import_module('%s')\n", module);
Printf(default_import_code, "%s = swig_import_helper()\n", module);
Printv(default_import_code, "del swig_import_helper\n", NULL);
if (builtin) {
if (!builtin) {
/* Import the C-extension module. This should be a relative import,
* since the shadow module may also have been imported by a relative
* import, and there is thus no guarantee that the C-extension is on
* sys.path. Relative imports must be explicitly specified from 2.6.0
* onwards (implicit relative imports raised a DeprecationWarning in 2.6,
* and fail in 2.7 onwards).
*
* First determine the shadow wrappers package based on the __name__ it
* was given by the importer that loaded it. Then construct a name for
* the module based on the package name and the module name (we know the
* module name). Use importlib to try and load it. If an attempt to
* load the module with importlib fails with an ImportError then fallback
* and try and load just the module name from the global namespace.
*/
Printv(default_import_code, "def swig_import_helper():\n", NULL);
Printv(default_import_code, tab4, "import importlib\n", NULL);
Printv(default_import_code, tab4, "pkg = __package__ if __package__ else __name__.rpartition('.')[0]\n", NULL);
Printf(default_import_code, tab4 "mname = '.'.join((pkg, '%s')).lstrip('.')\n", module);
Printv(default_import_code, tab4, "try:\n", NULL);
Printv(default_import_code, tab8, "return importlib.import_module(mname)\n", NULL);
Printv(default_import_code, tab4, "except ImportError:\n", NULL);
Printf(default_import_code, tab8 "return importlib.import_module('%s')\n", module);
Printf(default_import_code, "%s = swig_import_helper()\n", module);
Printv(default_import_code, "del swig_import_helper\n", NULL);
} else {
/*
* Pull in all the attributes from the C module.
*
* An alternative approach to doing this if/else chain was
* proposed by Michael Thon. Someone braver than I may try it out.
* proposed by Michael Thon at https://github.com/swig/swig/issues/691.
* Someone braver than I may try it out.
* I fear some current swig user may depend on some side effect
* of from _foo import *
*