m***@comcast.net
2016-01-09 22:52:50 UTC
I've been reading the recent archives of posts here and saw the
discussion of removing support for older versions of python in
swig-3.1.0. I think this area of thought overlaps a current problem
I'm having with swig and python3.
In python3 the way for a module (say a swig shadow file) to import
another module in the same package (the C wrappers generated by swig)
is:
# foo.py
from . import _foo
Here foo.py and _foo.so live in some subpackage. The
"from . import _foo" syntax works even with python3's new implicit
namespace packages (more on these later).
So, for just python3 (only) all that is needed is::
from . import _foo
And what swig spits out to support every version of python is
(-c++ -python -py3 -modern -O -naturalvar):
from sys import version_info
if version_info >= (3, 0, 0):
new_instancemethod = lambda func, inst, cls: _foo.SWIG_PyInstanceMethod_New(func)
else:
from new import instancemethod as new_instancemethod
if version_info >= (2, 6, 0):
def swig_import_helper():
from os.path import dirname
import imp
fp = None
try:
fp, pathname, description = imp.find_module('_foo', [dirname(__file__)])
except ImportError:
import _foo
return _foo
if fp is not None:
try:
_mod = imp.load_module('_foo', fp, pathname, description)
finally:
fp.close()
return _mod
_foo = swig_import_helper()
del swig_import_helper
else:
import _foo
del version_info
The above code generated by swig will not work with python's
implicit namespace packages:
https://www.python.org/dev/peps/pep-0420/
Implicit namespace packages seem great from a swig perspective
because they allow for portions of a package to be loaded from
different paths. So, for example the foo.py file could be under
/path1/pkg1/pkg2/foo.py and _foo.so could be under
/path2/pkg1/pkg2/_foo.so
Even more useful is that the foo.py file could be placed into a zip
file, frozen, or stored in some other way and the _foo.so could be on
some file system where the os can use it. With implicit namespace
packages all of these will work.
But not with the code swig is currently generating. The path
argument in find_module() forces a fail with implicit namespace
packages and the fallback to "import _foo" is looking for _foo.so in
the global namespace. My workaround works:
%pythonbegin %{
def impKludge(set=True):
import sys
if set:
from . import _foo
sys.modules['_foo'] = _foo
else:
del sys.modules['_foo']
impKludge()
%}
%pythoncode %{
impKludge(False)
del impKludge
%}
But this is ugly beyond description. So, I was going to try and
make a patch for swig that would cause it to simply spit out:
from . import _foo
if say -py3 and -modern were both used. Somehow I think there
should be a way to tell swig "Hey I'm using python3 and have no
interest at all in going back. Just generate code for python3".
Maybe there is already a way to do this that I'm missing? Otherwise,
I'm willing to help fix this issue in whatever way I can.
Mike
discussion of removing support for older versions of python in
swig-3.1.0. I think this area of thought overlaps a current problem
I'm having with swig and python3.
In python3 the way for a module (say a swig shadow file) to import
another module in the same package (the C wrappers generated by swig)
is:
# foo.py
from . import _foo
Here foo.py and _foo.so live in some subpackage. The
"from . import _foo" syntax works even with python3's new implicit
namespace packages (more on these later).
So, for just python3 (only) all that is needed is::
from . import _foo
And what swig spits out to support every version of python is
(-c++ -python -py3 -modern -O -naturalvar):
from sys import version_info
if version_info >= (3, 0, 0):
new_instancemethod = lambda func, inst, cls: _foo.SWIG_PyInstanceMethod_New(func)
else:
from new import instancemethod as new_instancemethod
if version_info >= (2, 6, 0):
def swig_import_helper():
from os.path import dirname
import imp
fp = None
try:
fp, pathname, description = imp.find_module('_foo', [dirname(__file__)])
except ImportError:
import _foo
return _foo
if fp is not None:
try:
_mod = imp.load_module('_foo', fp, pathname, description)
finally:
fp.close()
return _mod
_foo = swig_import_helper()
del swig_import_helper
else:
import _foo
del version_info
The above code generated by swig will not work with python's
implicit namespace packages:
https://www.python.org/dev/peps/pep-0420/
Implicit namespace packages seem great from a swig perspective
because they allow for portions of a package to be loaded from
different paths. So, for example the foo.py file could be under
/path1/pkg1/pkg2/foo.py and _foo.so could be under
/path2/pkg1/pkg2/_foo.so
Even more useful is that the foo.py file could be placed into a zip
file, frozen, or stored in some other way and the _foo.so could be on
some file system where the os can use it. With implicit namespace
packages all of these will work.
But not with the code swig is currently generating. The path
argument in find_module() forces a fail with implicit namespace
packages and the fallback to "import _foo" is looking for _foo.so in
the global namespace. My workaround works:
%pythonbegin %{
def impKludge(set=True):
import sys
if set:
from . import _foo
sys.modules['_foo'] = _foo
else:
del sys.modules['_foo']
impKludge()
%}
%pythoncode %{
impKludge(False)
del impKludge
%}
But this is ugly beyond description. So, I was going to try and
make a patch for swig that would cause it to simply spit out:
from . import _foo
if say -py3 and -modern were both used. Somehow I think there
should be a way to tell swig "Hey I'm using python3 and have no
interest at all in going back. Just generate code for python3".
Maybe there is already a way to do this that I'm missing? Otherwise,
I'm willing to help fix this issue in whatever way I can.
Mike