Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using absolute_import and handling relative module name conflicts in python

I really hope this is a simple case of me miss-understanding the complex Python2 import mechanisms. I have the following setup:

$> ls -ltr pypackage1 
total 3
-rw-r--r-- 1 pelson pelson   0 Aug 17 19:20 io.py
-rw-r--r-- 1 pelson pelson   0 Aug 17 19:20 __init__.py
-rw-r--r-- 1 pelson pelson  57 Aug 17 19:22 code.py
$> cat pypackage1/code.py 
from __future__ import absolute_import

import zipfile

i.e. I have nothing but a stub package with an empty __init__.py and io.py, and a 2 lines code.py file.

I can import pypackage1:

$> python -c "import pypackage1.code"

But I cannot run the code.py file:

$> python pypackage1/code.py
Traceback (most recent call last):
  File "pypackage1/code.py", line 3, in <module>
    import zipfile
  File "python2.7/zipfile.py", line 462, in <module>
    class ZipExtFile(io.BufferedIOBase):
AttributeError: 'module' object has no attribute 'BufferedIOBase'

Clearly the problem has to do with the zipfile module picking up my relative io module over the builtin io module, but I thought my from __future__ import absolute_import would have fixed that.

Thanks in advance for any help,

like image 387
pelson Avatar asked Aug 17 '12 18:08

pelson


People also ask

How do you resolve a name conflict in Python?

The easiest and most sane way to do it is to refactor you project and change the name of the file.

Should I use relative or absolute imports Python?

With your new skills, you can confidently import packages and modules from the Python standard library, third party packages, and your own local packages. Remember that you should generally opt for absolute imports over relative ones, unless the path is complex and would make the statement too long.

What is __ all __ in Python?

PACKAGES. In the __init__.py file of a package __all__ is a list of strings with the names of public modules or other objects. Those features are available to wildcard imports. As with modules, __all__ customizes the * when wildcard-importing from the package.

How do you use relative imports in Python?

Relative imports use dot(.) notation to specify a location. A single dot specifies that the module is in the current directory, two dots indicate that the module is in its parent directory of the current location and three dots indicate that it is in the grandparent directory and so on.


2 Answers

That's the correct behaviour. If you want to fix the error simply do not run from inside the package.

When you run a script which is inside the package, python wont interpret that directory as a package, thus adding the working directory to the PYTHONPATH. That's why the io module imported by the zipfile module is your io module and not the one inside the standard library.

I'd recommend to create a simple launcher script outside your package (or in a bin/scripts folder), and launch that. This script can simply contain something like:

from pypackage1 import code

code.main()

An alternative to this is to tell the python interpreter that the file that you want to execute is part of a module. You can do this using the -m command line option. In your case you would have to do:

python -m pypackage1.code

Note that the argument of -m should be the module name, not the file name.

like image 87
Bakuriu Avatar answered Sep 24 '22 06:09

Bakuriu


One solution would be to put from __future__ import absolute_import in the zipfile.py module. Although your module is using absolute import, the zipfile module is not.

Another option is to not run from your package directory. You probably shouldn't be running the interpreter from within the package directory.

like image 20
dsh Avatar answered Sep 24 '22 06:09

dsh