Discussion:
[Swig-devel] Python relative import
Paweł Tomulik
2016-06-20 09:25:11 UTC
Permalink
Hi,

I was just skimming through SWIG manual and found this snippet in docs
related to python imports
(http://swig.org/Doc3.0/SWIGDocumentation.html#Python_absrelimports)

from sys import version_info
if version_info >= (2, 7, 0):
from . import pkg2
import pkg1.pkg2.mod3
else:
import pkg2.mod3
del version_info


This is a code, which gets inserted by "swig -relativeimport" when
package/module things are used. It doesn't work in python < 2.5, because
relative import syntax (from . import pkg2) was introduced in 2.5:


Python 2.3.5 (#2, Oct 18 2006, 23:58:16)
[GCC 4.1.2 20061007 (prerelease) (Debian 4.1.1-16)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
import pkg1.mod2
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "pkg1/mod2.py", line 3
from . import pkg2
^
SyntaxError: invalid syntax

If it's a known issue (e.g. dropped support for py < 2.5) then just
don't mind (although it should be good to mention somewhere in docs
which versions of Python are supported).

Regards!
--
Paweł Tomulik
m***@comcast.net
2016-06-20 16:45:26 UTC
Permalink
Python 2.3.5 (#2, Oct 18 2006, 23:58:16) [GCC 4.1.2 20061007
(prerelease) (Debian 4.1.1-16)] on linux2 Type "help",
"copyright", "credits" or "license" for more information.
import pkg1.mod2
Traceback (most recent call last): File "<stdin>", line 1, in ?
^^^^^^

What is mod2.py and how was it created? I ask because the import
line in question is on line three. I don't think it is possible for
any swig generated code that would do an import to ever be on line
three.

Is mod2.py created by hand by copying the code snippet in from the
docs? If that is the case then something must be going on with
python-2.3 and this:

from sys import version_info
if version_info >= (2, 7, 0):
# Python 2.3 should not even get here to line 3
else:
# Python 2.3 *should* be using import pkg2.mod3 here.

Mike
Paweł Tomulik
2016-06-20 16:55:49 UTC
Permalink
Post by m***@comcast.net
Python 2.3.5 (#2, Oct 18 2006, 23:58:16) [GCC 4.1.2 20061007
(prerelease) (Debian 4.1.1-16)] on linux2 Type "help",
"copyright", "credits" or "license" for more information.
import pkg1.mod2
Traceback (most recent call last): File "<stdin>", line 1, in ?
^^^^^^
What is mod2.py and how was it created? I ask because the import
line in question is on line three. I don't think it is possible for
any swig generated code that would do an import to ever be on line
three.
The comment is about
http://swig.org/Doc3.0/SWIGDocumentation.html#Python_absrelimports

The above chapter contains an example with the following files:

pkg1/
pkg1/__init__.py
pkg1/mod2.py
pkg1/pkg2/__init__.py
pkg1/pkg2/mod3.py

where __init__.py are just empty files and the remaining files have the
following contents:



# pkg1/pkg2/mod3.py:
--------------------
class M3: pass



# pkg1/mod2.py:
---------------
from sys import version_info
if version_info >= (2, 7, 0):
from . import pkg2
import pkg1.pkg2.mod3
else:
import pkg2.mod3
del version_info
Post by m***@comcast.net
Is mod2.py created by hand by copying the code snippet in from the
docs?
Yes.
Post by m***@comcast.net
If that is the case then something must be going on with
from sys import version_info
# Python 2.3 should not even get here to line 3
This is a common gotcha. The code isn't EXECUTED, but it IS PARSED by
python interpreter. You can't just put arbitrary strings and disable
them using if/else. What about this?:


if False:
Zażółć tę gęślą jaźń
$%%$@ !@#$%^&*

???


You only can put a valid python code here, and "from . import pkg2" is
only valid in python 2.5 and later.
Post by m***@comcast.net
# Python 2.3 *should* be using import pkg2.mod3 here.
Mike
--
Pawel Tomulik
Paweł Tomulik
2016-06-20 17:05:15 UTC
Permalink
Post by m***@comcast.net
Python 2.3.5 (#2, Oct 18 2006, 23:58:16) [GCC 4.1.2 20061007
(prerelease) (Debian 4.1.1-16)] on linux2 Type "help",
"copyright", "credits" or "license" for more information.
import pkg1.mod2
Traceback (most recent call last): File "<stdin>", line 1, in ?
^^^^^^
What is mod2.py and how was it created? I ask because the import
line in question is on line three. I don't think it is possible for
any swig generated code that would do an import to ever be on line
three.
Is mod2.py created by hand by copying the code snippet in from the
docs? If that is the case then something must be going on with
from sys import version_info
# Python 2.3 should not even get here to line 3
# Python 2.3 *should* be using import pkg2.mod3 here.
Mike
BTW. I recall that my initial approach to the implementation of the
-relativeimport flag (https://github.com/swig/swig/pull/7) also assumed
that runtime dispatch should be used to switch between old and new
syntax for relative imports, but first tests showed that this breaks
older python versions. That's why I ended up with static dispatch based
on the -py3 SWIG flag. See
https://github.com/swig/swig/pull/7#issuecomment-18530786, especially
point 2.

Regards!
--
Pawel Tomulik
Paweł Tomulik
2016-06-29 10:47:12 UTC
Permalink
Post by m***@comcast.net
Python 2.3.5 (#2, Oct 18 2006, 23:58:16) [GCC 4.1.2 20061007
(prerelease) (Debian 4.1.1-16)] on linux2 Type "help",
"copyright", "credits" or "license" for more information.
import pkg1.mod2
Traceback (most recent call last): File "<stdin>", line 1, in ?
^^^^^^
What is mod2.py and how was it created? I ask because the import
line in question is on line three. I don't think it is possible for
any swig generated code that would do an import to ever be on line
three.
Is mod2.py created by hand by copying the code snippet in from the
docs? If that is the case then something must be going on with
from sys import version_info
# Python 2.3 should not even get here to line 3
# Python 2.3 *should* be using import pkg2.mod3 here.
Mike
So, any conclusions here?
--
Paweł Tomulik, tel. (22) 234 7925
Instytut Techniki Lotniczej i Mechaniki Stosowanej
Politechnika Warszawska
m***@comcast.net
2016-06-29 18:54:13 UTC
Permalink
...
Post by Paweł Tomulik
So, any conclusions here?
Perhaps the real issue is that the documentation is not 100%
accurate as to what gets put into the shadow file. What really gets
put into the shadow file is the following (which is not for the faint
of heart):

from sys import version_info as _swig_python_version_info
if _swig_python_version_info >= (2, 7, 0):
def swig_import_helper():
import importlib
pkg = __name__.rpartition('.')[0]
mname = '.'.join((pkg, '_bar')).lstrip('.')
try:
return importlib.import_module(mname)
except ImportError:
return importlib.import_module('_bar')
_bar = swig_import_helper()
del swig_import_helper
elif _swig_python_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('_bar', [dirname(__file__)])
except ImportError:
import _bar
return _bar
if fp is not None:
try:
_mod = imp.load_module('_bar', fp, pathname, description)
finally:
fp.close()
return _mod
_bar = swig_import_helper()
del swig_import_helper
else:
import _bar
del _swig_python_version_info


I'm not advocating that the above should be put into the
documentation. But perhaps the docs should be modified to fix the
inconsistency while not spelling out the exact details of how it
actually happens.

Mike
William S Fulton
2016-11-25 20:24:35 UTC
Permalink
Post by m***@comcast.net
...
Post by Paweł Tomulik
So, any conclusions here?
Perhaps the real issue is that the documentation is not 100%
accurate as to what gets put into the shadow file. What really gets
put into the shadow file is the following (which is not for the faint
from sys import version_info as _swig_python_version_info
import importlib
pkg = __name__.rpartition('.')[0]
mname = '.'.join((pkg, '_bar')).lstrip('.')
return importlib.import_module(mname)
return importlib.import_module('_bar')
_bar = swig_import_helper()
del swig_import_helper
from os.path import dirname
import imp
fp = None
fp, pathname, description = imp.find_module('_bar', [dirname(__file__)])
import _bar
return _bar
_mod = imp.load_module('_bar', fp, pathname, description)
fp.close()
return _mod
_bar = swig_import_helper()
del swig_import_helper
import _bar
del _swig_python_version_info
I'm not advocating that the above should be put into the
documentation. But perhaps the docs should be modified to fix the
inconsistency while not spelling out the exact details of how it
actually happens.
<https://lists.sourceforge.net/lists/listinfo/swig-devel>
Mike, documentation patches always welcome!

William

Loading...