Mausy5043 Mausy5043 - 2 months ago 7
Python Question

How to have python functions and classes available system-wide with an easy `import` statement

Introduction



I thought I'd try my hand at making a python module to make some of my libraries and functions available system-wide.
Google and StackExchange provide ample "solutions" and how-toos. But for some reason none of them seem to work for me. Obviously, I'm doing something wrong. But after days of trial & error I've decided to show you guys what I have and let you point out the obvious error to me ;-) Your help is much appreciated.

What I have



My GitHub project directory contains this tree:

$ tree /tmp/mausy5043-common-python
/tmp/mausy5043-common-python
├── docs
├── gitforcepull
├── LICENSE
├── mausy5043funcs
│   └── __init__.py
├── mausy5043libs
│   ├── __init__.py
│   ├── libdaemon3.py
│   └── libsmart3.py
├── README.md
├── setup.py
└── tests


libsmart3.py
is a python script that offers a
class SmartDisk():
. Both
__init__.py
scripts are empty.
libdaemon3.py
is a script that contains another class. It has the same problem but I'll use the
libsmart3
module as an example here.

I install this project as follows:

$ sudo python3 setup.py install
running install
running build
running build_py
creating build
creating build/lib
creating build/lib/mausy5043libs
copying mausy5043libs/libdaemon3.py -> build/lib/mausy5043libs
copying mausy5043libs/libsmart3.py -> build/lib/mausy5043libs
running install_lib
copying build/lib/mausy5043libs/libsmart3.py -> /usr/local/lib/python3.4/dist-packages/mausy5043libs
copying build/lib/mausy5043libs/libdaemon3.py -> /usr/local/lib/python3.4/dist-packages/mausy5043libs
byte-compiling /usr/local/lib/python3.4/dist-packages/mausy5043libs/libsmart3.py to libsmart3.cpython-34.pyc
byte-compiling /usr/local/lib/python3.4/dist-packages/mausy5043libs/libdaemon3.py to libdaemon3.cpython-34.pyc
running install_egg_info
Removing /usr/local/lib/python3.4/dist-packages/mausy5043_common_python-0.1dev.egg-info
Writing /usr/local/lib/python3.4/dist-packages/mausy5043_common_python-0.1dev.egg-info


What doesn't work



Now I want to use this class
SmartDisk()
in another python script. To do this I expected (was hoping) that I would be able to import the class directly -- thanks to the presence of the
__init__py
-- thus:

$ python3
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mausy5043libs import SmartDisk
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'SmartDisk'
>>>


OR

>>> from libsmart3 import SmartDisk
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: No module named 'libsmart3'
>>>


How I don't want it to work



What does work is this:

>>> from mausy5043libs.libsmart3 import SmartDisk


but this is not how it was advertised (ref: http://mikegrouchy.com/blog/2012/05/be-pythonic-__init__py.html )

What else did I try



I've tried to add
import libsmart3
in
mausy5043libs/__init__.py
. Doesn't work.

I've added
from libsmart3 import SmartDisk
in
mausy5043libs/__init__py
. No joy.

I've added an empty
__init__.py
in the project root under the assumption that python needs this. Didn't help.

EDIT
changes made: to
mausy5043libs/__init__py
as suggested by @user2357112

$ cat mausy5043libs/__init__.py
from .libsmart3 import SmartDisk
$ sudo python3 setup.py install
[... output removed ...]
$ python3
Python 3.4.2 (default, Oct 19 2014, 13:31:11)
[GCC 4.9.1] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from mausy5043libs import SmartDisk
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ImportError: cannot import name 'SmartDisk'


EDIT 2 : It turns out the solution provided by @user2357112 does indeed work. There was, obviously, a small oversight on my part. In
setup.py
the entry
mausy5043libs/__init__
was missing in the
py_modules
list.

Answer

You completely misread the sources you were working off of. If you want to be able to import SmartDisk directly from the mausy5043libs package, then mausy5043libs/__init__.py needs to import SmartDisk:

# in mausy5043libs/__init__.py
from .libsmart3 import SmartDisk

Then users of the package can import it the way you want:

# in code that wants to use SmartDisk
from mausy5043libs import SmartDisk

The article you linked includes this information under "What goes in __init__.py?", although they use pre-Python 3 implicit relative import syntax.

Comments