Project structure - Best practices

Rafe rafesacks at gmail.com
Mon Dec 1 09:54:35 CET 2008


On Nov 30, 11:43 pm, "Filip Gruszczyński" <grusz... at gmail.com> wrote:
> This is first time that I am building python application that is
> larger than a single module and I would like to do it right. I google
> it a bit, finding some stuff about not using src directory (which I
> have seen so many times, that I believed it be standard) and using
> packages. Still, there are few things, that I would like to achieve
> with this structure:
> * being able to use pychecker a lot - catching all typos in one shot
> instead of running app many times really saves me a lot of time
> * being able to write some unit tests
> * having clean division of code among packages and modules (I have
> seen some projects, where modules are pretty large - I would like to
> keep them logically divided, event if they stay smaller)
>
> My project is a tool for people interested in role playing games. My
> current structure looks something like this:
>
> /src
> rpgDirectory.py (main script, running the app)
>
> src/rpg
> plans.py
> support.py
> gui.py
> iosystem.py
>
> src/rpg/character
> model.py
> sheet.py
> gui.py
> handlers.py
> requirements.py
>
> The problem is, that modules from src/rpg/character use classes
> defined in support.py. Therefore I have to use absolute paths to
> import it and this works only, when I run rpgDirectory.py. When I use
> pychecker, it can't import this module and fails. Any suggestions, how
> can I avoid this and what structure should I use?
>
> --
> Filip Gruszczyński

Hi,

I have read in many places that relative imports aren't recommend as a
standard. This includes PEP 8 (http://www.python.org/dev/peps/
pep-0008/) which states:

" - Relative imports for intra-package imports are highly discouraged.
      Always use the absolute package path for all imports.
      Even now that PEP 328 [7] is fully implemented in Python 2.5,
      its style of explicit relative imports is actively discouraged;
      absolute imports are more portable and usually more readable."

...and I completely agree. I always use the standard import form
unless absolutely necessary. However, I use 'as' to shorten the path
to the last module. For example:
>>> import app.foo.bar as bar
>>> instance = bar.Class()

The only "relative" import I use when I am getting another module in
the same package. If I have:

app/
    __init__.py
    constants.py
    foo/
       __init__.py
       bar.py
       here.py
    utils/
        __init__.py

... and I am inside app/foo/here.py, I might have some imports at the
top of the module which look like this...

import app.constants as appC
import app.utils

import bar


Python will look for 'bar' in the local package before looking through
the python path. I could have imported constants as just "c", but
single letter variables are dangerous and I work with an application
where it is common in the community to use 'c' for
'constants' (regardless of the danger). Lastly, I could import
'app.utils' as 'utils', but this is such a common module name that I
like to preserve the name-space or at least prefix it (so I suppose
something like 'apputils' would be acceptable, but I'd only be saving
one character, the '.', so what's the point?).

I find that no matter how well I plan what my structure will be, I end
up making small changes such as flattening a sub-package or converting
a module to a sub-package to break things down further. As someone who
recently started learning python, I would recommend that you just make
a quick sketch of what you think might work and then just begin
coding. Adjust to logic along the way.

At some point planning begins to eat time rather than save it. get
through the fastest initial 80%, maybe push for a few more %, then
just go for it (I assume you have this luxury. If not then you
probably have a team that can help refine the plan anyway.)


Hope this helps.

- Rafe





More information about the Python-list mailing list