Best Practices for Internal Package Structure

Josh B. jabronson at gmail.com
Mon Apr 4 12:47:34 EDT 2016


My package, available at https://github.com/jab/bidict, is currently laid out like this:

bidict/
├── __init__.py
├── _bidict.py
├── _common.py
├── _frozen.py
├── _loose.py
├── _named.py
├── _ordered.py
├── compat.py
├── util.py


I'd like to get some more feedback on a question about this layout that I originally asked here: <https://github.com/jab/bidict/pull/33#issuecomment-193877248>:

What do you think of the code layout, specifically the use of the _foo modules? It seems well-factored to me, but I haven't seen things laid out this way very often in other projects, and I'd like to do this as nicely as possible.

It does kind of bug me that you see the _foo modules in the output when you do things like this:

>>> import bidict
>>> bidict.bidict
<class 'bidict._bidict.bidict'>
>>> bidict.KeyExistsError
<class 'bidict._common.KeyExistsError'>


In https://github.com/jab/bidict/pull/33#issuecomment-205381351 a reviewer agrees:

"""
Me too, and it confuses people as to where you should be importing things from if you want to catch it, inviting code like

```
import bidict._common

try:
    ...
except bidict._common.KeyExistsError:
    ...
```
ie. becoming dependent on the package internal structure.

I would be tempted to monkey-patch .__module__ = __name__ on each imported class to get around this. Maybe there are downsides to doing magic of that kind, but dependencies on the internals of packages are such a problem for me in our very large codebase, that I'd probably do it anyway in order to really explicit about what the public API is.
"""

Curious what folks on this list recommend, or if there are best practices about this published somewhere.

Thanks,
Josh



More information about the Python-list mailing list