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

Dart first impressions

I’m taking a introductory mobile development class this term, which is mainly taught in Flutter/Dart, so I’m in the initial stages of learning the Dart programming language at the moment. I enjoy learning new programming languages, though that’s not to say there aren’t some pain points at times (looking at you, JavaScript).

In practice, Dart is pretty tied up with Flutter, as it seems the main paradigm in which it’s used is in combination with Flutter for mobile development. That said, I won’t be talking a lot about Widgets and such, as I haven’t gotten too deep into the Flutter side of things yet. But, here’s a few initial impressions of the Dart programming language.

The language definitely feels modern, with lots of syntactic sugar and powerful methods/functions built in. It’s much more like programming in Python than C++, for instance. Just look at this gorgeously simple class constructor.

 Planet({required this.name, required this.description});

That’s it. The brackets signify that the contents are keyword arguments, and the this.name syntax assigns the argument to the corresponding class attribute automatically. Lovely! The required, of course, marks these as non-optional.

Dart is strongly typed, which I like. However, it can also infer types, so something like this is fine.

var x = 21;

It also has enough flexibility to allow non-specific types, as in code like the following.

dynamic getRandomListElement(List<dynamic> list) {
  if (list.isNotEmpty) {
    return list[Random().nextInt(list.length)];
  } else {
    return null;
  } 
}

This will work equally well on a list<int> or list<String>. Cool stuff.

Now, let’s talk about null safety. Dart is not messing around when it comes to null safety. I’m onboard with the basic idea of it, but it has caused some annoyances so far. For instance, the compiler will complain about the following code.

  Planet getNextLegDestination() {

    String answer = '';
    Planet planet;

    while (answer != 'Y' && answer != 'N') {
      answer = promptGetResponse(
        'Shall I randomly choose a planet for you to visit? (Y or N)'
      );
      if (answer == 'Y') {
        planet = hostSystem.getRandomPlanet();
      } else if (answer == 'N') {
        planet = hostSystem.getNamedPlanet();
      } else {
        print('Sorry, I didn\'t get that.');
      }
    }
    return planet;
  }

It’s convinced that the return planet; at the end is not null safe, even though the while loop can never cease without assigning a value to planet. My workaround was to do this instead, which required adding a default null planet attribute to another class.

Planet planet = hostSystem.invalidPlanet;
// Planet planet;

Another solution would be to mark variables as nullable (e.g., Planet? planet;), but this requires adapting variables types and return types all over the place. Having to have default, non-null assignments definitely seems like it will be problematic at times, especially when you have a complex class that maybe isn’t built to have a ‘blank’ instantiation. The whole thing ends up a bit awkward for me, but maybe I just need more time to get used to it. As the documentation states, “With null safety, your runtime null-dereference errors turn into edit-time analysis errors.”, which is definitely a good reason to get used to dealing with this.

For a few final thoughts, the official documentation is pretty good, but certainly not the best I’ve used. I also find it interesting that pretty much everything is an object — even int. I’m not sure how to feel about this!

Overall, I’m finding Dart easy to learn and use, though I don’t really have any information at this point about how fast it runs, or deeper details about its implementation. Grade so far: B+.

Song of the week: In the Shade of the Sun — Kapitan Korsakov

Learning new systems

This week I’ve been thinking a lot about independent learning. The more CS topics I learn about, the more I see how much I don’t know. There are so many languages, frameworks, systems, concepts, etc. to explore — being an expert on all of them is impossible.

One thing I hear a lot is that, in CS fields, you can’t think of your learning as done just because you’ve got a degree in your hand. These days, I don’t think any of us, regardless of field, have that luxury. The next job/role/position will always ask us to learn new things and conquer new concepts. This isn’t a bad thing. Learning can be fun! But, let’s not forget another piece of wisdom…

Fun and Failure both start out the same way." George Michael's  inspirational poster. #ArrestedDevel… | Inspirational posters, George  michael, Arrested development

If you know a surefire way to not fail at life and learning, please share it with the rest of the class. In the meantime, I’ll just have to do my pathetic best.

Step one: don’t get overwhelmed. There’s a saying I like about murdering an endangered species for crass, caloric concerns…

How Do You Eat An Elephant? – Ayat Saleh

When learning a new system, I like to start with a high-level overview. Getting the sky-high view helps me contextualize what I’m about to learn, where this system fits, what I might want to use it for, etc. Not exactly groundbreaking stuff, but hey, it works!

I’m not ashamed to admit that I often turn to Wikipedia for this. There are myriad useful articles with broad overviews of CS concepts, though I generally don’t find it quite as useful for learning how to use a new tool or framework.

A good book on the topic should include a good overview as well. I just started reading Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow by Aurélien Géron, and it’s chapter 1 overview of machine learning is the best overview I’ve read in a while. I felt a lot less stressed about diving into this large, complex, and nebulous topic after getting to grips with just a few broad strokes.

Step two: get your hands dirty. Playing with code examples and making toy, hello world programs and the like is a great way to remember what you’re learning and come up with new questions and avenues to explore. One great thing about them thar’ internets is that you can often find a good online tutorial that includes basic information along with the opportunity to practice immediately.

Step three: don’t worry about learning everything all at once. It’s not often practical to read a book on the new topic cover to cover, especially as we often find ourselves needing to learn about several new topics at once. I do enjoy learning all the little details and tricks you can find with a fuller approach, but it’s usually necessary to be a bit more focused.

Working on small, incremental steps to what I actually need to learn for my current project is a practical approach. Early on, I’ll often be knees-deep in a code editor, working at a glacial pace while looking something up for every other line of code. I’ll know I’ve gotten more comfortable once the official documentation no longer reads like lorem ipsum and I can refer to it freely without needing to refer to it constantly.

Step four: ????.

Step five: you’re an expert! Congrats! Wipe your chops, give a quick eulogy for the last extant elephant, and kick that imposter syndrome to the curb.

Song of the week: And Saints – Sleigh Bells

Game AI, please stop cheating…

…and git gud.

I’ve been noticing more and more, over my many years wasted spent playing the vidya games, that game AI is really dumb. The typical, as in universal, fix to enable difficulty is for the AI to just straight up cheat. But you don’t find a suitable chess opponent by playing someone a lot worse and giving them extra pieces. Wouldn’t it be nice if AI provided more difficulty by being smarter instead?

The dumbness problem is one I first acutely noticed in Total War: Empire. The AI, or, more accurately, the computer opponents controlled by scripts, were in a state of complete failure.

For strangers to the 4X genre, this is a game where you rule a nation, trying to build all the things, recruit all the armies, conquer all the cities, and eventually accumulate enough bits and bobbins to declare yourself the bestest of all nations, thereby winning the game.

To call the other, computer-controlled nations AI is a bit misleading, because they have no actual intelligence, and don’t really seek to emulate it in any meaningful way. But in any case, this is the term that’s stuck around for referring to your computer-controlled opponents, so I’ll keep using it. Also, the problem of dumb AI is no way unique to 4X games, but I’ll be focusing on them because they’re the best example of it in my opinion.

So, these AIs were having some issues. One nation, I believe it was France, in this game loosely based on the real-world colonial era (a lot less fun in real life than in game form, or so I hear) was marching an army to my border, then to its capital, then back, stuck in an endless loop of doing absolutely nothing. To be fair, the other AIs weren’t faring much better, mostly treading water in various unproductive ways while patiently waiting to be stomped by the smart-brained human player.

A notable engagement was my war with Spain, which had been stuck in limbo for a few dozen turns. In that time, nothing had really happened. I had a strong navy and had blockaded all their ports for several decades, starving their economy. I couldn’t be bothered with a land invasion to conquer their cities, so I figured I would blockade all their ports and take a diplomatic approach, essentially trying to extract concessions for a peace treaty.

The AI was not onboard with this plan. Instead, they decided that the proper cost of a peace treaty for the war they were disastrously losing, which they offered me every turn, should be that I pay them about 5 times more than everything in my treasury. While they made this demand over and over, they also marched their armies back and forth in their territories, seemingly stuck in their own loop.

The particular, highly visible AI failures I noticed in this game really made me pay attention to what the opponents were doing, and the more attention I payed, the more I realized that at no point in this game were any of the AI opponents capable of a remotely robust understanding of the state of the game or of responding to it appropriately. The 4X genre is especially interesting to me when it comes to thinking about game AI, because it’s a genre where there’s a clear need for really good AI, met by an absolute lack of anything that meets this challenge.

4X games are inherently very complicated. There’s a lot of moving parts to fiddle with, and you proceed to fiddle with them for a very long period of time, min-maxing your civilization, constantly angling towards victory. I have to imagine this makes it very hard to make a good AI, and indeed I’ve yet to encounter one.

In theory, human opponents would be ideal for anyone seeking a real challenge in these games. But not many of us can commit to playing campaigns that take 10s of hours with a group of friends, beholden to the whims of when everyone happens to be able to play. There are some options for more flexible multiplayer, but none of these have ever appealed to me much either. Imagine if we had an AI in these games that could actually compete.

To be fair, it is possible to achieve a reasonable amount of challenge. Setting the difficulty to max in Civilization, for example, is mostly going to provide a satisfactory challenge, at least for some amount of time. But in order to achieve this, the AI turns into a bunch of dirty cheaters.

To allow the rudimentary AI to compete, they get things like a tremendous head start at the beginning of the game, coupled with passive boosts to pretty much everything they do to the tune of 50-100% for the entire game. As a consequence of how these games work in practice, with a strong snowball effect, we should really consider these bonuses to be multiplicative, stacking on top of each other.

Starting with two cities means the AI can immediately build twice as much stuff. A 75% bonus to production on top of this means they can immediately build three times as much stuff. If they push this productive power into expansion, they ought to soon be able to produce 10 times as much stuff, or more, quickly leaving you in the dust. But eventually, using your human brain, with intelligent play, you’ll overtake them. It would be easy to think this makes you some sort of galaxy brained genius, but it’s more to do with their incompetence. It’s actually kind of insane how much they cheat, considering they’re still ultimately designed to lose.

For nongamers, please permit me a Sportsball metaphor. Imagine you’re playing a game of the Basketballs. You’re alone, and on the other side of the court is 10 NBA pros. They all have a couple extra arms, cuz that seems like it’d be helpful. Also, your basket is at a height of 5 feet instead of 10, every goal they score counts for double points, and they start at 20. But ultimately, you know you’re going to win because 3 of them are just spinning in circles in place, 2 others will endlessly pass the ball back and forth between them whenever they lay hands on it, another is glitched out with that little loading wheel over his face, and the rest seem unclear on what a basket is, what a ball is, and how can Basket Ball?

You know what would really push the envelope for 4X games, and perhaps all games? An AI that plays the game even slightly well instead of cheating. I would love to see machine learning in this context. Many games are clearly too complex for a team of humans to sit there and write good, scripted AI for. Or, at the very least, it’s not enough of a priority for the developers to be willing to spend the time and resources it would take. But machine learning could theoretically train smart, capable AIs while using an acceptable amount of development resources.

Also built in to the machine learning model is how the neural networks need to be trained. You’ll want multiple difficulty settings, of course, which could come in the form of the same AI at various stages in its training, with the most difficult being the most up-to-date. Some finessing would be required, sure, but it seems like a natural fit, at least from a high-level view.

Of course, there are obstacles as well. For instance, if the game is updated sufficiently, does the AI have to be retrained from scratch? Will even small updates degrade AI performance, as the AI is trained on an older version of the game? Is it feasible to train the AI in the actual game itself, or will that be too slow to institute the required number of iterations? And, how smart do we actually want the AI to be?

Still, for me, the potential for the application of machine learning to make game AI smarter is much more exciting than the next generation of graphics, VR, or any of the other technologies the industry seems the most interested in pushing and pursuing (cough, metaverse, cough, NFTs, cough). I just hope that someday soon I have the chance to write another post complaining that game AI is cheating by being too damn smart for my squishy human brain.

Song of the week: Civilian – Wye Oak