Web.py NameError When Importing Module in Module
Question: I am creating a web app using web.py on python 2.7.3. I have the following
folder structure:

    
    
    start_app.py
    /app
       __init__.py
       /models
          __init__.py
          ActionModel.py
          AreaModel.py
       /controllers
          __init__.py
          world.py
       /views
    

Whenever I freshly start the app using `python start_app.py`, and visit
`world/surrounding` I get the following error

    
    
    <type 'exceptions.ImportError'> at /world/surrounding
    cannot import name AreaModel
    Python  /home/dev/app/models/ActionModel.py in <module>, line 13
    Web     GET http://localhost:5000/world/surrounding
    

Line 13 is simply: `from app.models import AreaModel` but I don't see why
python is complaining here.

If I comment this importing line, it runs fine. However, if I call a different
URL, e.g. `world/view`, I get an error that AreaModel is not defined. Once I
uncomment the line, it works fine again for all cases (i.e. /surrounding and
/view).

I am suspecting that this has something to do with the fact that I am
"importing in circles", i.e. world.py imports AreaModel, AreaModel imports
ActionModel and ActionModel imports AreaModel. I doubt that this is 'the
pythonic way' to do things or even the 'MVC way', so I would very much
appreciate your enlightening me how to do this properly.

Note: app is not in my PYTHONPATH, but I don't think it is needed here, since
start_app.py is in the top-level directory and according to
[this](http://stackoverflow.com/questions/13221021/cannot-get-imports-to-work-
in-web-py-project) all modules should be available.

Basically, what it comes down to is: I need the models' functionalities in
both the controllers and the models. Is it good practice to "import in
circles"? Or is there a nicer approach to do this? Also, is this problem
related to python in general or just web.py?

**Update:** Added **init**.py files, I had them, but did not include in
original question. Sorry for that.

**Update:** ActionModel.py includes (among others) a class named BaseAction
and a few functions, which return instances or subclasses of BaseAction
depending on what type of Action we are dealing with. They are called using
e.g. `ActionModel.get_by_id()`

@matthew-trevor : Are you suggesting in _a)_ that I should move those
functions `get_by_id()` into a class ActionModel?

    
    
    #actionmodel.py
    class ActionModel(object):
        def __init__(arg1, arg2, area_class):
            self.area = area_class()
    
        def get_by_id(self, id):
            return BaseAction(id)
    
    class BaseAction(object):
        def __init__(id):
            pass
    

I don't see how this should remedy my import problems though.


Answer: **The Immediate Problem**

You cannot import from folders, but you _can_ import from packages. You can
turn any folder into a package by adding an `__init__.py` file to it:

    
    
    start_app.py
    /app
       __init__.py
       /models
          __init__.py
          ActionModel.py
          AreaModel.py
       /controllers
          __init__.py
          world.py
       /views
          __init__.py
    

I'm guessing that `ActionModel.py` includes a class of the same name. If so, I
recommend renaming the file to `actionmodel.py` to distinguish it from the
class.

**Circular imports**

> Is it good practice to "import in circles"? Or is there a nicer approach to
> do this?

It's not only bad practice, it just won't work. There are a couple of ways to
get around this, which will mostly depend on what you're trying to do:

a. In `AreaModel`, import the `ActionModel` module and then reference anything
you want to use in it via attribute lookup and vice versa:

    
    
    # areamodel.py
    import actionmodel
    
    def foo():
        action = actionmodel.ActionModel(...)
    

As long as the references are inside class or function definitions, it will
only occur at run time and not during importing, so the circular reference is
avoided.

b. Turn `models` into a module and put both `ActionModel` and `AreaModel` code
inside it.

c. Move the shared code/functionality for `ActionModel` and `AreaModel` into a
base module they both import from.

d. Make your `ActionModel` class (or whatever) accept a class as an input,
then pass `AreaModel` into it in `world.py` (ditto for `AreaModel`). This way,
`ActionModel` doesn't need to contain a reference to `AreaModel`, it just has
to know what to do with it:

    
    
    # actionmodel.py
    class ActionModel(object):
        def __init__(arg1, arg2, area_class):
            self.area = area_class()
    
    # areamodel.py
    class AreaModel(object):
        def __init__(action_class):
            self.action = action_class()
    
    # world.py
    from actionmodel import ActionModel
    from areamodel import AreaModel
    
    action = ActionModel('foo', 'bar', AreaModel)
    area = AreaModel(ActionModel)
    

This is known as object composition.

