Python: main

Breaking down the Python from

It’s installed with:


Files are packaged using a file. E.g.


Here’s a sample script (/usr/local/bin/awslogs – source code:



Path to Python. No idea why there’s an @.


# -*- coding: utf-8 -*-

Specifies the encoding.


Imported as used later on. E.g. sys.argv[0]


from awslogs.bin import main

means: from the package awslogs.bin import the module main.

How does Python find these packages?

They’re in it’s path. E.g.


What is this dist-info directory?

It’s created by Wheel – one of Python’s packaging formats. See:


the mainfunction is from awslogs/ here:


More on sys.path:


if __name__ == '__main__':

If run from the command line (e.g. python ) then __name__ will == '__main__'. Otherwise, if it’s been run as a module then __name__ will be the name of the module.


sys.argv[0] = re.sub(r'(-script\.pyw?|\.exe)?$', '', sys.argv[0])




Python > parsing JSON


Note: [] are for lists, {} are for dictionaries.

We can parse it with Python like this:


Python: getting rid of the ‘u’ symbol when outputting text

I find it really annoying that whenever Python prints a string it prints out a u when it’s Unicode.

When you copy and paste that stuff it retains it all. If you’re copying and pasting JSON you’re left with broken JSON. Here’s how to get rid of it:


Python > Inspect an object


print dir(<my object>)

where <my object> is your object name.


dirreturns the list of names in the current local scope.


vars returns the __dict__attribute for a module, class or instance.


__dict__ is a dictionary or other mapping object used to store an object’s writable attributes.


Isolated Development Environments with virtualenv


pip install virtualenv

Create a directory for your virtualenvs

mkdir .virtualenvs
cd .virtualenvs

Use virtualenv

Let’s say we want to create a virtualenv called test:

virtualenv test

. test/bin/activate

and the prompt should change to show:


Now, installing a package will install it in this virtualenv. E.g.  pip install pylintwill install pylintinto this virtualenv under .virtualenvs/test/bin

and the PATH is changed so you use stuff under this virtualenv. E.g. which python:


Deactivate virtualenv (also clears prompt with brackets): deactivate

Activate virtualenv: . ./test/bin/activate



pip install virtualenvwrapper

Edit ~/.profile

source /usr/local/bin/

export PROJECT_HOME="$HOME/Code/Python"

This gives us some extra commands – mkvirtualenv, setvirtualenvproject, workon:

mkvirtualenv <virtualenv>

Makes the virtualenv in your .virtualenvs directory.


workon <virtualenv>

E.g. workon test

This doesn’t change us to the code directory though. You can do this by cding to the code directory and using:


This ties the current directory with the virtualenv. Handy if you need to move directories.


mkproject – creates a project in your code directory, sets up a virtualenv, cd’s to the code directory and activates the virtualenv.


Python Packages – use setuptools and pip

Many ways of creating, distributing and installing packages. E.g.

distutils, setuptools, easy_install, ez_setup, pip.

Multiple formats:

egg, wheel, source dist.

To clear up this mess, the Python Packaging Authorits (PyPA) was setup. Advice is, if creating and distributing a package:

  1. use setuptools

Note: distutils is discontinued and merged into setuptools. easy_install is also merged into setuptools.

If installing a package, use pip and virtualenv.

Note: from Python 3.4, pip comes pre-installed.

Also homebrew installs pip by default with Python.


Notes on  pip

pip list

pip show <specific package>

pip search query

Requirements file

pip freeze > requirements.txt: save project dependencies into requirements.txt

pip install -r requirements.txt: install packages listed in file


Why Python sucks – why I hate Python: a Python rant

Suck #1

I started following a super-basic tutorial on Python as I’d learned the basics over the years and wanted to learn again from scratch.

The very first thing they do is:


>> import requests

Simple, right?


I got:

So now I’m spending half an hour trying to debug the most basic thing in a Python tutorial. This is clearly a sign of things to come.

Various StackOverflow answers describing complicated solutions that did not help:

Turns out the solution was to do:

pip install requests

Fortunately, I had pip installed. But basically a complete beginner would have that as an additional hurdle to overcome.


''=> current working directory

then searches through directories.

/usr/local/lib/python2.7/site-packages => third party packages

Note: on Debian this is called dist-packages.

Suck #2

Following a script that mentions os.environ I get:

NameError: global name 'os' is not defined

Turns out I need to import os. Python folks – can’t this be done automatically? It’s not hard. Just see a variable that matches a package you know and import it. DONE. Kind of like the Mac’s AutoSave. Let’s get out of the ’80s here…

Suck #3

Again, following that script I copy and paste part into a REPL to try it out. As the indentation is different I get:

IndentationError: unexpected indent

Groan. So, I have to go through the script manually adding indents. Again, let’s get rid of indent restrictions. Stupid.

Suck #4

Gibberish logs and debug output.

A method I had copied was clearly wrong. When I attempted to use it from the REPL with ec2 = get_client("ec2") I got:

What a pile of gibberish. To be clear – 21 lines and 1629 characters of gibberish.

Why not print it out in Assembly just to make it less clear?! Has anyone made any effort whatsoever on making this more user-friendly?

Suck #5

I’ve got an object that’s been returned using a pretty standard library. i.e.

client = boto3.client('ec2')

There is no output when I run it from the REPL. Sounds OK.

Let’s inspect this object. Looking for introspectionI find:

Ooh. Python has a strong set of introspection features. OK, let’s try


Jeez! Another 6 lines of gibberish.

How about client.getattr()? Surely that’s got to return something?!

Why can’t they just return messages like: AttributeError: 'EC2' object has no attribute 'getattr' and get it over with. Then you could have some debug parameter to find out more if any of the additional text above is actually useful.

At least the very user-friendly underscore underscore dict underscore underscore method (i.e. __dict__) helps figure out what’s going on behind the scenes. That was an easy one to figure out without digging through Stackoverflow. Not.

Suck #6

Let’s follow the 4 simple steps here:

1. Download or clone the repository.

No problem.

2. Open terminal and point to root of repository. Type: pip install -r requirements.txt

I get (in red):

awscli 1.15.53 has requirement botocore==1.10.52, but you’ll have botocore 1.12.23 which is incompatible.

I’ve no idea now whether I need to upgrade awscli, downgrade botocore. Or even why I’m getting this message.

It also fails with:

Could not install packages due to an EnvironmentError: [Errno 13] Permission denied: ‘/usr/local/man’
Consider using the --user option or check the permissions.

Why on earth didn’t the maintainers bother to mention that you might need to use --user in the install instructions.

I run:

pip install --user -r requirements.txt

and no longer see the red fails. I’ve no idea why the awscli, botocore errors have disappeared.

3. Run server with: python3 Alternatively: ./ runserver

Great. 2 options to fail.

Let’s try the second:

./ runserver

and the nice simple error message:

I don’t understand why they couldn’t make this less simple to understand. Perhaps another 1500 lines of gibberish to reduce legibility would have helped. E.g. they could have thrown in some random characters to help confuse the end user.

Given that the instructions say:

Python 3.4+

and I find this issue buried on github:

which helpfully suggests ignoring the official (faulty) install instructions and using (the also incorrect):

pip3 install -r requirements.txt

The correct install instructions are:

pip3 install --user -r requirements.txt

Handily there’s also no mention that:


will take 10 seconds before it starts generating output and so appearing it’s not working.

4. Access HQ with: http://localhost:5000


Did I say I hate Python?


Suck #7

Why on earth use 4 spaces?!

Let me rephrase it. If you use one less or more of an invisible character your code will break. Or if you swap it out for another invisible character that looks exactly the same (i.e. the tab) it will also break.

Brilliant design idea.

Let’s find something analogous in the real world.

If you reach for the right glass you can have a drink of water.

But if you reach for the wrong glass (that looks exactly the same) it breaks.