Managing imports in a Python project

I’ve been working on a group project this term, and we’ve been having some trouble with imports. The project structure is shown (with some details removed for simplicity).

project
│   .gitignore
│   README.md
│   requirements.txt
│   setup.py
│
└───project_name
    │   __init__.py
    │
    ├───data
    │       data_loader.py
    │       feature_extractor.py
    │       feature_recorder.py
    │       gtzan_utils.py
    │       __init__.py
    │
    ├───ml
    │   │   __init__.py
    │   │
    │   └───c
    │           ml_algo_c.py
    │           training_script.py
    │           write_features_script.py
    │           __init__.py
    │
    ├───resources
    │       .gitignore
    │
    └───tests
            testing.py
            __init__.py

Please forgive the placeholder project_name. I swear we’ll replace it with something brilliant any day now.

The problem is, I need to access the data classes in training_script.py. I spent some time trying to get relative imports working the way I wanted. Python did not like this at all, and I wound up with this terrible code.

import sys
import os
import time

import tensorflow as tf

# This import works fine since it's in the same folder
# as training_script.py
from ml_c import MlAlgoC

# Doing work to crawl up the top-level directory of the project
# and append that directory to sys.path so that Python can
# find our project files
script_dir = os.path.dirname(__file__)
mymodule_dir = os.path.join(script_dir, '..', '..')
sys.path.append(mymodule_dir)

# The preceding code was necessary to make these imports
# of local project files work.
# This is terrible!
import data.data_loader as dl           # noqa: E402
import data.feature_recorder as fr      # noqa: E402

# Note the inline comments needed to stop the linter
# from complaining about imports not being at the
# top of the file. Ugh!

In fact, the whole group was having this issue. In most languages, you would just do something like this.

# Not in Python, but many languages would allow an import
# like this
import '../../data/data_loader.py'
import '../../data/feature_recorder.py'

But no dice, as Python does not allow any such import syntax. What’s the problem?

When looking for imports, Python crawls sys.path, which is a list of paths where Python expects to find modules and packages. This, by default, holds the paths Python needs to find Python library files and installed packages. It also contains the folder in which your Python execution started.

When I’m trying to run my script files in the project_name/ml/c folder, either directly through the command line, or using my IDE (VS Code), the local folder Python supplies to sys.path is the c folder. Python has no idea how to find the data folder from here — it can only find modules/packages at the same level or lower in the tree.

One note here is that PyCharm might automatically add your project folder to sys.path, so those using PyCharm might not have this issue.

Another note: you could argue that the script files should be located together in a bin folder somewhere, but that doesn’t really help with this particular problem.

I looked into various solutions for this, and the cleanest one I could find is to simply install the project like you would any other Python package. Then, you can access it using the same absolute import syntax you would use for any built-in Python library or installed package.

This sounds problematic, though, because do we really want a duplicate of our project files installed somewhere else on our system? Worse, are we going to have to update/reinstall the package every time we change a single line of code? Finally, what if we just want a small project and don’t want to do extra work to make it installable as a robust, reusable package?

Luckily, pip has a method to handle this. Using an editable install, you can do a very lightweight install that essentially sets up a symbolic link to your project folder, wherever it is located. The command is simple.

pip install -e path/to/SomeProject

# Or, just use this while navigated to the directory
# where your setup.py file is located
pip install -e .

Then, Python can access your project folder just like it would any installed package. Since this links to your actual project folder, any changes you make will be reflected and available in your imports immediately. You are just linking from the Python installed package folder directly to your real project directory.

Of course, you will need a setup.py file to make this work. Fortunately, you don’t need all the fields filled in that a true installable package would require. If you just want to ease your intra-project imports, a setup.py as simple as this is sufficient.

from setuptools import setup


setup(name='project_name')

The following pip commands may be helpful as well.

# Display info about your installed project
pip show project_name

# Uninstall your project if you want to clean up later
# Don't worry, this just removes the symbolic link and
# doesn't delete any of your project files in its
# original home.
pip uninstall project_name

With this setup, that abysmal code from earlier becomes much cleaner and more Pythonic.

import sys
import time

import tensorflow as tf

from project_name.ml.c.ml_algo_c import MlAlgoC
import project_name.data.data_loader as dl
import project_name.data.feature_recorder as fr

This will work wherever you’re doing these imports, as Python finds your project files in the same place as other installed packages!

We’re no longer trying to awkwardly force Python to do imports in a way it doesn’t want to. If you can’t beat them…

(join them… learn their secrets… then plot your revenge)

Song of the week: Cat Clyde – All the Black (acoustic)

Top n lyrics, aka women who rock (and/or roll)

I’ve been totally swamped working on my group’s machine learning project the last couple of weeks, so, today, I wanted to write about something completely different, relaxing, and fun.

There will be no math or science involved, I assure you! Instead, I’ll just take a moment to climb out of the IDE swamp and list some of the lines of lyrics I really enjoy. Without further ado, here they are in what turns out is (mostly) alphabetical order since I sourced them trolling through some playlists.

Berlin Blues Song – Alice Phoebe Lou
It Ruffled up my feathers and it barked right up my tree
When suddenly it seemed all the fingers were pointing on up at me
And the footsteps in the sand
Were all getting washed up by the sea
To leave me in stitches, bursting at the seams
Bursting at the seams

When the sun came out to greet me
I only saw the wolves from my dreams
This is my Berlin blues song
Sometimes life can get a little wrong
But it won't be long
Cuz it just makes me strong

Lovely. I’ve italicized my favorite line.

Nude as the News – Cat Power
I still have a flame gun
For the cute ones
To burn out all your tricks
And I saw your hand
With a loose grip
On a very tight ship

I stiilll, have a flame gun!

Avant Gardener – Courtney Barnett
Reminds me of the time
When I was really sick and I
Had too much Pseudoephedrine and I
Couldn't sleep at night

Halfway down high street, Andy looks ambivalent
He's probably wondering what I'm doing getting in an ambulance

The paramedic thinks I'm clever cuz I play guitar
I think she's clever cuz she stops people dying

Anaphylactic and super hypocondriactic
Should've stayed in bed today
I much prefer the mundane

It was very difficult to not just paste the whole song in there. Courtney Barnett has a lot of great songs, but the first I ever heard is still by far my favorite.

Dog Years – Daddy Issues
If you could be anything
You would be the worst thing
A dry patch when you’re sledding
And waking up with my lip bleeding
Here we are in the driveway
Deciding I have more to lose
But you should go home to Chicago
And take a long walk off the Navy Pier

Oh no, you scratched until I bled
I hope you choke on your own spit in your own bed
'Cause I know, I know where it ends
We’re not gonna be friends
In dog years you’re dead

Another great song, what more is there to say?

The Lion’s Roar – First Aid Kit
Now the pale morning sings of forgotten things
She plays a tune for those who wish to overlook
The fact that they've been blindly deceived
By those who preach and pray and teach
But she falls short and the night explodes in laughter

I have slightly mixed feeling about this song. The first part is amazing, but the rest is just good, so it sadly falls short of being one of my all-time favorites. But damn if I don’t love that first verse.

No Duh – K Flay
Hear your shit, I treat it like my bitch, onto the next jam
Just kidding, I treat my bitches with respect
Talking politics to boys while they're kissing on my neck
...
...
More popular than gefilte fish at a seder
My calculators TI-89, you're stuck on 83
While you all wait in line, I'm on that VIP
...
...
The dopest animal from here to Senegal
Flow so menstrual I need a tampon on the track
Got a couple bars to kill it and some monkeys on my back

I had a pick a few top lines spread throughout this one, as the song is pretty much a relentless barrage of cutting and hilarious lines. I especially enjoy the cock-eyed wink towards the misogyny that features in far too many popular songs.

Angelene (Demo) – PJ Harvey
My first name Angelene
Prettiest mess you've ever seen

Love for money is my sin
Any man calls, I'll let him in

Rose is my color, and white
Pretty mouth and green my eyes
I see men come and go

But there'll be one who will collect my soul and come to me
Two-thousand miles away
He walks upon the coast
Two-thousand miles away

There’s so much in PJ Harvey’s performance here. The Demo version of the song is just incredible. It’s dark and gorgeously grungy. Talk about a rock and a hard place — I always imagine this lovely 2k-mile-away gent ominously emerging from the sea.

Belispeak – Purity Ring
Grandma, my hands have wandered
And my legs, my little legs are getting weak
Bid lend me your wispy frame
And guard my powers
Guard my precious powers in its cage

Grandma, I’ve been unruly
In my dreams and with my speech
Drill little holes into my eyelids
That I might see you
That I might see you when I...
Sleep

Well, to be fair, having holes in your eyelids would make you an absolute boss at staring contests.

If Children Were Wishes – Wye Oak
If children were wishes,
My mother spent hers on impossible things
My brother was money,
My sister was love, and I was world peace
...
...
...
...
And so I suppose this is
Just how it goes no matter how I try,
I just have to watch you get
Weaker and weaker till you finally die

But I have to remember
The wish of my mother and all that I'm worth,
Which will only come true
When there are no more of us left on this earth

I enjoy this song a lot. It’s also nice to have in my pocket in case I ever find myself in a ‘who can name the most depressing song ever’ contest.

Tibetan Pop Stars – Hop Along
How content are the ones, with simple demands?
They meet their fiancés, cherry picking out in Canada
While cursing the river, a seven fingered man
His three sleepless wives, all equally sick of him

Just a taste of this brilliant gem. Truly one of my favorite songs ever. It’s funny, insightful, different, and filled with powerful imagery all over the damn place.

Well, that’s all I’ve got time for, so I guess that will have to do. Definitely not an exhaustive list of my favorites, but a very nice set of lyrics and/or songs nonetheless.

Songs of the week:

Berlin Blues Song - Alice Phoebe Lou
Nude as the News – Cat Power
Avant Gardener – Courtney Barnett
Dog Years – Daddy Issues
The Lion’s Roar – First Aid Kit
No Duh – K Flay
Angelene (Demo) – PJ Harvey
Belispeak – Purity Ring
If Children Were Wishes – Wye Oak
Tibetan Pop Stars – Hop Along