Custom Python module importing code
Add optional moduleimport attribute to %module so that the default module import code can be overridden. See the "Searching for the wrapper module" documentation in Python.html. Example: %module(moduleimport="import _foo") foo $module also expands to the low-level C/C++ module name, so the following is the same as above %module(moduleimport="import $module") foo Issue https://github.com/swig/swig/issues/769
This commit is contained in:
parent
da1dd2ffd2
commit
2a42031b08
6 changed files with 135 additions and 56 deletions
|
|
@ -5,6 +5,19 @@ See the RELEASENOTES file for a summary of changes in each release.
|
|||
Version 3.0.11 (in progress)
|
||||
============================
|
||||
|
||||
2016-12-01: wsfulton
|
||||
[Python] Issue https://github.com/swig/swig/issues/769
|
||||
Add optional moduleimport attribute to %module so that the
|
||||
default module import code can be overridden. See the "Searching for the wrapper module"
|
||||
documentation in Python.html. Example:
|
||||
|
||||
%module(moduleimport="import _foo") foo
|
||||
|
||||
$module also expands to the low-level C/C++ module name, so the following is the
|
||||
same as above
|
||||
|
||||
%module(moduleimport="import $module") foo
|
||||
|
||||
2016-11-30: olly
|
||||
[PHP] Add support for PHP7. PHP5's C extension API has changed substantially
|
||||
so you need to use -php7 to specify you want PHP7 compatible wrappers. The
|
||||
|
|
|
|||
|
|
@ -509,7 +509,7 @@ If using static linking, you might want to rely on a different approach
|
|||
|
||||
<p>
|
||||
To use your module, simply use the Python <tt>import</tt> statement. If
|
||||
all goes well, you will be able to this:
|
||||
all goes well, you will be able to run this:
|
||||
</p>
|
||||
|
||||
<div class="targetlang"><pre>
|
||||
|
|
@ -6037,7 +6037,7 @@ zipimporter requires python-3.5.1 or newer to work with subpackages.
|
|||
<p>
|
||||
When SWIG creates wrappers from an interface file, say foo.i, two Python modules are
|
||||
created. There is a pure Python module module (foo.py) and C/C++ code which is
|
||||
built and linked into a dynamically (or statically) loaded module _foo
|
||||
built and linked into a dynamically (or statically) loaded low-level module _foo
|
||||
(see the <a href="Python.html#Python_nn3">Preliminaries section</a> for details). So, the interface
|
||||
file really defines two Python modules. How these two modules are loaded is
|
||||
covered next.
|
||||
|
|
@ -6064,7 +6064,43 @@ pure Python module uses to find the C/C++ module is as follows:
|
|||
</ol>
|
||||
|
||||
<p>
|
||||
As an example suppose foo.i is compiled into foo.py and _foo.so. Assuming
|
||||
The Python code implementing the loading logic described above is quite complex to handle multiple
|
||||
versions of Python, but it can be replaced with custom code.
|
||||
This is not recommended unless you understand the full intricacies of importing Python modules.
|
||||
The custom code can be specified by setting the <tt>moduleimport</tt> option of the <tt>%module</tt> directive with the appropriate import code. For example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%module(moduleimport="import _foo") foo
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
<p>
|
||||
The special variable <tt>$module</tt> will also be expanded into the low-level C/C++ module name, <tt>_foo</tt> in the case above.
|
||||
When you have more than just a line or so then you can retain the easy
|
||||
readability of the <tt>%module</tt> directive by using a macro. For
|
||||
example:
|
||||
</p>
|
||||
|
||||
<div class="code">
|
||||
<pre>
|
||||
%define MODULEIMPORT
|
||||
"
|
||||
print 'Loading low-level module $module'
|
||||
import $module
|
||||
print 'Module has loaded'
|
||||
"
|
||||
%enddef
|
||||
|
||||
%module(moduleimport=MODULEIMPORT) foo
|
||||
</pre>
|
||||
</div>
|
||||
|
||||
|
||||
<p>
|
||||
Now let's consider an example using the SWIG default loading logic.
|
||||
Suppose foo.i is compiled into foo.py and _foo.so. Assuming
|
||||
/dir is on PYTHONPATH, then the two modules can be installed and used in the
|
||||
following ways:
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -63,6 +63,7 @@ CPP_TEST_CASES += \
|
|||
python_director \
|
||||
python_docstring \
|
||||
python_extranative \
|
||||
python_moduleimport \
|
||||
python_nondynamic \
|
||||
python_overload_simple_cast \
|
||||
python_pickle \
|
||||
|
|
|
|||
7
Examples/test-suite/python/python_moduleimport_runme.py
Normal file
7
Examples/test-suite/python/python_moduleimport_runme.py
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
import python_moduleimport
|
||||
|
||||
if python_moduleimport.simple_function(99) != 99:
|
||||
raise RuntimeError("simple_function")
|
||||
|
||||
if python_moduleimport.extra_import_variable != "custom import of _python_moduleimport":
|
||||
raise RuntimeError("custom import")
|
||||
14
Examples/test-suite/python_moduleimport.i
Normal file
14
Examples/test-suite/python_moduleimport.i
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
%define MODULEIMPORT
|
||||
"
|
||||
#print 'Loading low-level module $module'
|
||||
import $module
|
||||
#print 'Module has loaded'
|
||||
extra_import_variable = 'custom import of $module'
|
||||
"
|
||||
%enddef
|
||||
|
||||
%module(moduleimport=MODULEIMPORT) python_moduleimport
|
||||
|
||||
%inline %{
|
||||
int simple_function(int i) { return i; }
|
||||
%}
|
||||
|
|
@ -565,6 +565,7 @@ public:
|
|||
* interface file to enable director generation.
|
||||
*/
|
||||
String *mod_docstring = NULL;
|
||||
String *moduleimport = NULL;
|
||||
{
|
||||
Node *mod = Getattr(n, "module");
|
||||
if (mod) {
|
||||
|
|
@ -605,6 +606,7 @@ public:
|
|||
}
|
||||
mod_docstring = Getattr(options, "docstring");
|
||||
package = Getattr(options, "package");
|
||||
moduleimport = Getattr(options, "moduleimport");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -779,6 +781,7 @@ public:
|
|||
}
|
||||
|
||||
/* If shadow classing is enabled, we're going to change the module name to "_module" */
|
||||
String *default_import_code = NewString("");
|
||||
if (shadow) {
|
||||
String *filen = NewStringf("%s%s.py", SWIG_output_directory(), Char(module));
|
||||
// If we don't have an interface then change the module name X to _X
|
||||
|
|
@ -814,13 +817,13 @@ public:
|
|||
mod_docstring = NULL;
|
||||
}
|
||||
|
||||
Printv(f_shadow, "\nfrom sys import version_info as _swig_python_version_info\n", NULL);
|
||||
Printv(default_import_code, "from sys import version_info as _swig_python_version_info\n", NULL);
|
||||
|
||||
if (!builtin && fastproxy) {
|
||||
Printv(f_shadow, "if _swig_python_version_info >= (3, 0, 0):\n", NULL);
|
||||
Printf(f_shadow, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module);
|
||||
Printv(f_shadow, "else:\n", NULL);
|
||||
Printv(f_shadow, tab4, "from new import instancemethod as new_instancemethod\n", NULL);
|
||||
Printv(default_import_code, "if _swig_python_version_info >= (3, 0, 0):\n", NULL);
|
||||
Printf(default_import_code, tab4 "new_instancemethod = lambda func, inst, cls: %s.SWIG_PyInstanceMethod_New(func)\n", module);
|
||||
Printv(default_import_code, "else:\n", NULL);
|
||||
Printv(default_import_code, tab4, "from new import instancemethod as new_instancemethod\n", NULL);
|
||||
}
|
||||
|
||||
/* Import the C-extension module. This should be a relative import,
|
||||
|
|
@ -840,42 +843,39 @@ public:
|
|||
* ImportError then fallback and try and load just the module name from
|
||||
* the global namespace.
|
||||
*/
|
||||
Printv(f_shadow, "if _swig_python_version_info >= (2, 7, 0):\n", NULL);
|
||||
Printv(f_shadow, tab4, "def swig_import_helper():\n", NULL);
|
||||
Printv(f_shadow, tab8, "import importlib\n", NULL);
|
||||
Printv(f_shadow, tab8, "pkg = __name__.rpartition('.')[0]\n", NULL);
|
||||
Printf(f_shadow, tab8 "mname = '.'.join((pkg, '%s')).lstrip('.')\n",
|
||||
module);
|
||||
Printv(f_shadow, tab8, "try:\n", NULL);
|
||||
Printv(f_shadow, tab8, tab4, "return importlib.import_module(mname)\n",
|
||||
NULL);
|
||||
Printv(f_shadow, tab8, "except ImportError:\n", NULL);
|
||||
Printf(f_shadow, tab8 tab4 "return importlib.import_module('%s')\n",
|
||||
module);
|
||||
Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module);
|
||||
Printv(f_shadow, tab4, "del swig_import_helper\n", NULL);
|
||||
Printv(f_shadow, "elif _swig_python_version_info >= (2, 6, 0):\n", NULL);
|
||||
Printv(f_shadow, tab4, "def swig_import_helper():\n", NULL);
|
||||
Printv(f_shadow, tab8, "from os.path import dirname\n", NULL);
|
||||
Printv(f_shadow, tab8, "import imp\n", NULL);
|
||||
Printv(f_shadow, tab8, "fp = None\n", NULL);
|
||||
Printv(f_shadow, tab8, "try:\n", NULL);
|
||||
Printf(f_shadow, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module);
|
||||
Printf(f_shadow, tab8 "except ImportError:\n");
|
||||
Printv(default_import_code, "if _swig_python_version_info >= (2, 7, 0):\n", NULL);
|
||||
Printv(default_import_code, tab4, "def swig_import_helper():\n", NULL);
|
||||
Printv(default_import_code, tab8, "import importlib\n", NULL);
|
||||
Printv(default_import_code, tab8, "pkg = __name__.rpartition('.')[0]\n", NULL);
|
||||
Printf(default_import_code, tab8 "mname = '.'.join((pkg, '%s')).lstrip('.')\n", module);
|
||||
Printv(default_import_code, tab8, "try:\n", NULL);
|
||||
Printv(default_import_code, tab8, tab4, "return importlib.import_module(mname)\n", NULL);
|
||||
Printv(default_import_code, tab8, "except ImportError:\n", NULL);
|
||||
Printf(default_import_code, tab8 tab4 "return importlib.import_module('%s')\n", module);
|
||||
Printf(default_import_code, tab4 "%s = swig_import_helper()\n", module);
|
||||
Printv(default_import_code, tab4, "del swig_import_helper\n", NULL);
|
||||
Printv(default_import_code, "elif _swig_python_version_info >= (2, 6, 0):\n", NULL);
|
||||
Printv(default_import_code, tab4, "def swig_import_helper():\n", NULL);
|
||||
Printv(default_import_code, tab8, "from os.path import dirname\n", NULL);
|
||||
Printv(default_import_code, tab8, "import imp\n", NULL);
|
||||
Printv(default_import_code, tab8, "fp = None\n", NULL);
|
||||
Printv(default_import_code, tab8, "try:\n", NULL);
|
||||
Printf(default_import_code, tab4 tab8 "fp, pathname, description = imp.find_module('%s', [dirname(__file__)])\n", module);
|
||||
Printf(default_import_code, tab8 "except ImportError:\n");
|
||||
/* At here, the module may already loaded, so simply import it. */
|
||||
Printf(f_shadow, tab4 tab8 "import %s\n", module);
|
||||
Printf(f_shadow, tab4 tab8 "return %s\n", module);
|
||||
Printv(f_shadow, tab8 "try:\n", NULL);
|
||||
Printf(default_import_code, tab4 tab8 "import %s\n", module);
|
||||
Printf(default_import_code, tab4 tab8 "return %s\n", module);
|
||||
Printv(default_import_code, tab8 "try:\n", NULL);
|
||||
/* imp.load_module() handles fp being None. */
|
||||
Printf(f_shadow, tab4 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module);
|
||||
Printv(f_shadow, tab8, "finally:\n", NULL);
|
||||
Printv(f_shadow, tab4 tab8 "if fp is not None:\n", NULL);
|
||||
Printv(f_shadow, tab8 tab8, "fp.close()\n", NULL);
|
||||
Printv(f_shadow, tab8, "return _mod\n", NULL);
|
||||
Printf(f_shadow, tab4 "%s = swig_import_helper()\n", module);
|
||||
Printv(f_shadow, tab4, "del swig_import_helper\n", NULL);
|
||||
Printv(f_shadow, "else:\n", NULL);
|
||||
Printf(f_shadow, tab4 "import %s\n", module);
|
||||
Printf(default_import_code, tab4 tab8 "_mod = imp.load_module('%s', fp, pathname, description)\n", module);
|
||||
Printv(default_import_code, tab8, "finally:\n", NULL);
|
||||
Printv(default_import_code, tab4 tab8 "if fp is not None:\n", NULL);
|
||||
Printv(default_import_code, tab8 tab8, "fp.close()\n", NULL);
|
||||
Printv(default_import_code, tab8, "return _mod\n", NULL);
|
||||
Printf(default_import_code, tab4 "%s = swig_import_helper()\n", module);
|
||||
Printv(default_import_code, tab4, "del swig_import_helper\n", NULL);
|
||||
Printv(default_import_code, "else:\n", NULL);
|
||||
Printf(default_import_code, tab4 "import %s\n", module);
|
||||
|
||||
if (builtin) {
|
||||
/*
|
||||
|
|
@ -890,22 +890,22 @@ public:
|
|||
* globals()[attr] = getattr(_foo, attr)
|
||||
*
|
||||
*/
|
||||
Printf(f_shadow, "# pull in all the attributes from %s\n", module);
|
||||
Printv(f_shadow, "if __name__.rpartition('.')[0] != '':\n", NULL);
|
||||
Printv(f_shadow, tab4, "if _swig_python_version_info >= (2, 7, 0):\n", NULL);
|
||||
Printv(f_shadow, tab8, "try:\n", NULL);
|
||||
Printf(f_shadow, tab8 tab4 "from .%s import *\n", module);
|
||||
Printv(f_shadow, tab8 "except ImportError:\n", NULL);
|
||||
Printf(f_shadow, tab8 tab4 "from %s import *\n", module);
|
||||
Printv(f_shadow, tab4, "else:\n", NULL);
|
||||
Printf(f_shadow, tab8 "from %s import *\n", module);
|
||||
Printv(f_shadow, "else:\n", NULL);
|
||||
Printf(f_shadow, tab4 "from %s import *\n", module);
|
||||
Printf(default_import_code, "# pull in all the attributes from %s\n", module);
|
||||
Printv(default_import_code, "if __name__.rpartition('.')[0] != '':\n", NULL);
|
||||
Printv(default_import_code, tab4, "if _swig_python_version_info >= (2, 7, 0):\n", NULL);
|
||||
Printv(default_import_code, tab8, "try:\n", NULL);
|
||||
Printf(default_import_code, tab8 tab4 "from .%s import *\n", module);
|
||||
Printv(default_import_code, tab8 "except ImportError:\n", NULL);
|
||||
Printf(default_import_code, tab8 tab4 "from %s import *\n", module);
|
||||
Printv(default_import_code, tab4, "else:\n", NULL);
|
||||
Printf(default_import_code, tab8 "from %s import *\n", module);
|
||||
Printv(default_import_code, "else:\n", NULL);
|
||||
Printf(default_import_code, tab4 "from %s import *\n", module);
|
||||
}
|
||||
|
||||
/* Delete the _swig_python_version_info symbol since we don't use it elsewhere in the
|
||||
* module. */
|
||||
Printv(f_shadow, "del _swig_python_version_info\n", NULL);
|
||||
Printv(default_import_code, "del _swig_python_version_info\n", NULL);
|
||||
|
||||
if (modern || !classic) {
|
||||
Printv(f_shadow, "try:\n", tab4, "_swig_property = property\n", "except NameError:\n", tab4, "pass # Python < 2.2 doesn't have 'property'.\n\n", NULL);
|
||||
|
|
@ -1053,8 +1053,13 @@ public:
|
|||
Printv(f_shadow, "# This file is compatible with both classic and new-style classes.\n", NIL);
|
||||
}
|
||||
Printv(f_shadow_py, "\n", f_shadow_begin, "\n", NIL);
|
||||
Printv(f_shadow_py, "\n", f_shadow_builtin_imports, "\n", NIL);
|
||||
Printv(f_shadow_py, f_shadow, "\n", NIL);
|
||||
if (moduleimport) {
|
||||
Replaceall(moduleimport, "$module", module);
|
||||
Printv(f_shadow_py, moduleimport, NIL);
|
||||
} else {
|
||||
Printv(f_shadow_py, default_import_code, NIL);
|
||||
}
|
||||
Printv(f_shadow_py, "\n", f_shadow, "\n", NIL);
|
||||
Printv(f_shadow_py, f_shadow_stubs, "\n", NIL);
|
||||
Delete(f_shadow_py);
|
||||
}
|
||||
|
|
@ -1077,6 +1082,9 @@ public:
|
|||
Printf(f_begin, "static PyTypeObject *builtin_bases[%d];\n\n", max_bases + 2);
|
||||
Wrapper_pretty_print(f_init, f_begin);
|
||||
|
||||
Delete(default_import_code);
|
||||
Delete(f_shadow_begin);
|
||||
Delete(f_shadow);
|
||||
Delete(f_header);
|
||||
Delete(f_wrappers);
|
||||
Delete(f_builtins);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue