How to structure python packages without repeating top level name for import

Question:

I’m brand new at python package management, and surely have done something wrong. I was encouraged to create a directory structure as follows:

bagoftricks
├── bagoftricks
│   ├── bagoftricks
│   │   ├── __init__.py
│   │   └── bagoftricks.py
│   └── __init__.py
├── README.md
└── setup.py

bagoftricks.py contains two functions, levenshtein() and geofind().

I would like to call these as:

import bagoftricks

x = bagoftricks.levenshtein(arg1,arg2) 

Instead, I find I have to do this:

import bagoftricks

x = bagoftricks.bagoftricks.levenshtein(arg1,arg2) 

Is there a better way to organize my packages in the first place, without the naming redundancy?

UPDATE

So, I followed Avichal Badaya’s instructions below, and removed one level of nesting. That is, I now have…

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   └── bagoftricks.py
├── README.md
└── setup.py

However, to call this package, I still have…

from bagoftricks.bagoftricks import geofind()

or

import bagoftricks

then

>>> bagoftricks.bagoftricks.geofind()

Rather than the desired….

from bagoftricks import geofind()

or

import bagoftricks

>>> bagoftricks.geofind()

I cannot remove that extra layer of nesting. When I try, by analogy, to remove one more level of nesting, so that my module is flat, as:

bagoftricks
├── __init__.py
├── bagoftricks.py
├── README.md
└── setup.py

I cannot build the package at all…

$ python setup.py build
running build
running build_py
error: package directory 'bagoftricks' does not exist

What’s the secret for natural imports like standard packages use, without redundant top-level name imports?

Asked By: Mittenchops

||

Answers:

Follow following structure :

bagoftricks 
    ── bagoftricks
    │ ├── __init__.py
    │ └── bagoftricks.py 
    ├── README.md
    └── setup.py

and then you should be able to use it as :

from bagoftricks.bagoftricks import levenshtein, geofind

but after you make the change in folder structure do :-

pip uninstall <your package name mostly mentioned in setup.py>

and reinstall the package

meanwhile check your setup.py

#!/bin/env python
import os.path
from setuptools import setup, find_packages

def current_path(file_name):
    return os.abspath(os.path.join(__file__, os.path.pardir, file_name))

setup(
    name = 'bagoftricks',
    version = '0.1',
    include_package_data = True,
    packages=find_packages(),
)

setup might have some other parameters too. I hope it works for you.

Answered By: Avichal Badaya

The first level “bagoftricks” is fine. That’s just the name of your “project” so to speak. In the you have a setup.py, and other files that tell the packaging systems what they need to know.

You can then have the code directly in this module, or in a src directory. You can even go as far as just having this structure:

bagoftricks
├── bagoftricks.py
├── README.md
└── setup.py

But I would not recommend that, mostly because you might want to reorganize things later, and it’s easier if you already have a “proper” package. Also most people, tools and docs assume you have a package, so it’s easier.

So the minimum would be:

bagoftricks
├── bagoftricks
│   └── __init__.py
├── README.md
└── setup.py

With __init__.py containing the functions you want to import. You then use these functions like this:

from bagoftricks import levenshtein, anotherfunction

Once that __init__.py becomes too big, you want to split it up in several modules, giving you something like this:

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   ├── anothermodule.py
│   └── levenshtein.py
├── README.md
└── setup.py

Your __init__.py should then import the functions from the various modules:

from bagoftricks.levenshtein import levenshtein
from bagoftricks.anothermodule import anotherfunction

And then you can still use them like like you did before.

Answered By: Lennart Regebro

with the updated structure you posted

bagoftricks
├── bagoftricks
│   ├── __init__.py
│   └── bagoftricks.py
├── README.md
└── setup.py

into bagoftricks/__init__.py import all functions that you need

__init__.py
from bagoftricks import geofind, levenshtein

into a different program you can do the follwing

from bagoftricks import geofind
import bagoftricks; bagoftricks.geofind(); bagoftricks.bagoftriks.geofind()

note that you can import as well a wild card

from bagoftricks import *
Answered By: silviud
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.