2

I have a Python package hosted on PyPA called Airship which has the following code in __init__.py:

import os
from airship import sync

class suppress_stdout_stderr(object): # http://stackoverflow.com/questions/11130156
    def __init__(self):
        self.null_fds = [os.open(os.devnull,os.O_RDWR) for x in range(2)]
        self.save_fds = (os.dup(1), os.dup(2))

    def __enter__(self):
        os.dup2(self.null_fds[0], 1)
        os.dup2(self.null_fds[1], 2)

    def __exit__(self, *_):
        os.dup2(self.save_fds[0], 1)
        os.dup2(self.save_fds[1], 2)
        os.close(self.null_fds[0])
        os.close(self.null_fds[1])

def main():
    with suppress_stdout_stderr():
        sync()

sync() is defined in __main__.py, and I have these lines in setup.py to define the entry point as a script:

entry_points={
    'console_scripts': [
        'airship=airship:main'
    ]
}

When I run airship after having installed it from pip on a Python 2.7.9 installation, it runs as expected (that is, no output).

When I try to do the same having installed the same package from pip on a Python 3.4.3 installation, I get this error:

Traceback (most recent call last):
  File "C:\Python34\lib\runpy.py", line 170, in _run_module_as_main
    "__main__", mod_spec)
  File "C:\Python34\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "C:\Python34\Scripts\airship.exe\__main__.py", line 5, in <module>
  File "C:\Python34\lib\site-packages\airship\__init__.py", line 2, in <module>
    from airship import sync
ImportError: cannot import name 'sync'

What is causing this and how can I fix it?

(Note: I have only tried running airship on a Python 3.x version of pip on Windows, which is where I encountered this issue. I have managed to successfully run airship on Python 2.x installations on both OS X and Debian).

Carlos Liam
  • 305
  • 2
  • 10

1 Answers1

2

In python 3 you need to use explicit relative imports, so to import a top level sync module in your project:

from . import sync

If sync is a submodule of airship do this:

from .airship import sync

The relative import style is was added to python 2.4, 2.5 and 2.6 with PEP 328, but it wasn't until python 3 that implicit relative imports were removed.

krock
  • 28,904
  • 13
  • 79
  • 85
  • i don't think this is just a python 3 thing, as i have also needed to do this in 2.6.5 – the_constant May 18 '15 at 00:29
  • according to [PEP 328](https://www.python.org/dev/peps/pep-0328/) relative imports are supported back to python 2.4 – krock May 18 '15 at 00:38
  • Downvoting because this answer mixes up what is absolute and what is relative. – user2357112 May 18 '15 at 00:38
  • @user2357112 please feel free to edit for clarification where you think it needs it. – krock May 18 '15 at 00:42
  • `sync()` is a function, not a module. This doesn't answer my question. However, is it possible to import `__main__.py` as a module, from `__init__.py`, and then just call `module.sync()`? – Carlos Liam May 18 '15 at 00:50