views:

1249

answers:

5

I am trying to organize some modules for my own use. I have something like this:

lib/
  __init__.py
  settings.py
  foo/
    __init__.py
    someobject.py
  bar/
    __init__.py
    somethingelse.py

In lib/__init__.py, I want to define some classes to be used if I import lib. However, I can't seem to figure it out without separating the classes into files, and import them in __init__.py.

Rather than say:

    lib/
      __init__.py
      settings.py
      helperclass.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib.helperclass import Helper

I want something like this:

    lib/
      __init__.py  #Helper defined in this file
      settings.py
      foo/
        __init__.py
        someobject.py
      bar/
        __init__.py
        somethingelse.py

from lib.settings import Values
from lib import Helper

Is it possible, or do I have to separate the class into another file?

EDIT

OK, if I import lib from another script, I can access the Helper class. How can I access the Helper class from settings.py?

The example here describes Intra-Package References. I quote "submodules often need to refer to each other". In my case, the lib.settings.py needs the Helper and lib.foo.someobject need access to Helper, so where should I define the Helper class?

+4  A: 

Edit, since i misunderstood the question:

Just put the Helper class in __init__.py. Thats perfectly pythonic. It just feels strange coming from languages like Java.

Richard Levasseur
You misunderstood. I want to eliminate the helperClass.py file if possible.
scottm
Richard isn't the only one who misunderstood. Your example should be working. What is the traceback?
Troy J. Farrell
Well, then I read the docs correctly. So, now I just made a test case and it works fine.
scottm
I have the same setup in my package, but I'm getting an ImportError "cannot import name Helper"
scottm
I think my problem is that I'm trying to import the Helper class from settings.py, how could I do that?
scottm
+4  A: 

You just put them in __init__.py.

So with test/classes.py being:

class A(object): pass
class B(object): pass

... and test/__init__.py being:

from classes import *

class Helper(object): pass

You can import test and have access to A, B and Helper

>>> import test
>>> test.A
<class 'test.classes.A'>
>>> test.B
<class 'test.classes.B'>
>>> test.Helper
<class 'test.Helper'>
Aaron Maenpaa
That's not working. I get a NameError.
scottm
Where are you doing the import from?
Aaron Maenpaa
Say I want to import Helper from lib/settings.py?
scottm
That will almost certainly result in a circular import (settings will import test and test will import settings)... which will produce the NameError you describe. If you want helpers that are used inside the package you should define an internal module that your code uses.
Aaron Maenpaa
Helpers in __init__.py should be for external users to simplify your API.
Aaron Maenpaa
External users have no use for Helper. Let's say the Helper class is a wrapper around a sql connection, and the other classes want to use it. I put it in the top most part of the tree thinking all sub-modules would have access.
scottm
If it's not part of the API, then __init__.py really isn't the place for it. lib/internal.py or similar would be much better (which has the double purpose of reducing the likelihood of circular imports).
Aaron Maenpaa
+1  A: 

Richard is right. Stack Overflow markup messed up his answer. He meant import the class into lib/__init__.py. (I can't edit his answer or I would...)

Troy J. Farrell
+1  A: 

Yes, it is possible. You might also want to define __all__ in __init__.py files. It's a list of modules that will be imported when you do

from lib import *
vartec
+3  A: 
  1. 'lib/'s parent directory must be in sys.path.

  2. Your 'lib/__init__.py' might look like this:

    from . import settings # or just 'import settings' on old Python versions
    class Helper(object):
          pass
    

Then the following example should work:

from lib.settings import Values
from lib import Helper

Answer to the edited version of the question:

__init__.py defines how your package looks from outside. If you need to use Helper in settings.py then define Helper in a different file e.g., 'lib/helper.py'.

.
|   `-- import_submodule.py
    `-- lib
    |-- __init__.py
    |-- foo
    |   |-- __init__.py
    |   `-- someobject.py
    |-- helper.py
    `-- settings.py

2 directories, 6 files

The command:

$ python import_submodule.py

Output:

settings
helper
Helper in lib.settings
someobject
Helper in lib.foo.someobject

# ./import_submodule.py
import fnmatch, os
from lib.settings import Values
from lib import Helper

print
for root, dirs, files in os.walk('.'):
    for f in fnmatch.filter(files, '*.py'):
        print "# %s/%s" % (os.path.basename(root), f)
        print open(os.path.join(root, f)).read()
        print


# lib/helper.py
print 'helper'
class Helper(object):
    def __init__(self, module_name):
        print "Helper in", module_name


# lib/settings.py
print "settings"
import helper

class Values(object):
    pass

helper.Helper(__name__)


# lib/__init__.py
#from __future__ import absolute_import
import settings, foo.someobject, helper

Helper = helper.Helper


# foo/someobject.py
print "someobject"
from .. import helper

helper.Helper(__name__)


# foo/__init__.py
import someobject
J.F. Sebastian
How could I import the Helper class in the settings.py file in my example?
scottm
I don't understand why that's circular. If settings.py needs Helper and say foo.someobject.py needs Helper, where do you suggest I define it?
scottm
wow, the word "helper" really starts to loose meaning in that example. However, you've shown me what I was looking for.
scottm
@J.F. Sebastian +1
Aaron Maenpaa