Friday, November 21, 2014

Setting Up a Python Project Skeleton

This article will show you some example project skeletons and what's needed to bootstrap something up, yourself. Let's get to it.

Prerequisites: This guide was written for Mac OS X users.

Project Layout

The simplest project is going to contain the following folders and files, at minimum:

|~project/
| |~test/
| | |-__init__.py
| | `-test_main.py
| |-main.py
| |-README.md
| `-setup.py

This setup lays out most of the files at the root level. You'll find a main.py which contains your program's source code, a test directory which contains the unit tests for main.py file and all the standard boilerplate files. The README.md file is standard for all github projects and contains the documentation for your program. If your project requires a little bit more structure, consider the following layout:

|~project/
| |+bin/
| |~project/
| | |~test/
| | | |-__init__.py
| | | `-test_project.py
| | |-__init__.py
| | `-project.py
| |-README.md
| `-setup.py

Building the Skeleton

Alright, let's run some commands in the terminal. We're going to want to install some programs before we start laying out our files. You'll want to use a version of Python that's managed by homebrew, and use pip over easy_install because it's superior in many ways and constantly updated. Prior to installing Python, you'll want to install GCC, which comes with XCode or Command Line Tools. The following commands assume you're on Mac OS X.

# Install Homebrew
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

# Install Python 2.7 which comes with Setuptools and pip
brew install python

# Install virtualenv
sudo pip install virtualenv

# Create the project files
# Replace "project" with the project name
mkdir project; cd project
mkdir project bin
touch __init__.py project.py

mkdir project/test
touch project/test/test_project.py
touch README.md
touch setup.py

Setting up setup.py

The most basic implementation of a setup.py file is as follows. We'll talk about setup.py in depth in a follow up article.

try:
  from setuptools import setup
except ImportError:
  from distutils.core import setup

config = {
  'description': 'Project description',
  'author': 'Name',
  'url': 'Home page of the application',
  'download_url': 'Download link',
  'author_email': 'me@gmail.com',
  'version': '0.1.0',
  'install_requires': ['pytest'], #dependencies
  'packages': ['NAME'],
  'scripts': [],
  'name': 'projectname'
}

setup(**config)

Setting Up a Virtual Environment

Think of a virtual environment as a way to isolate Python projects from one another. Why is this necessary, you ask? Every Python application you write comes with its own set of dependencies that you install by using pip install commands. Rather than installing these globally, you can install them into virtual environments with Ian Bicking's virtualenv. Let's set up a virtual environment for our skeleton:

virtualenv venv

# Activate the virtualenv
source venv/bin/activate

# Install py.test
pip install pytest

Note: If you're using fish, you can activate the virtualenv by running . venv/bin/activate.fish

Running a Boilerplate Unit Test

Populate your project/project/test/test_project.py file with the following:

def func(x):
    return x * 2

def test_answer():
    assert func(2) == 5

Then, just run py.test from inside project/project and you should see the following failed unit test output:

===== test session starts =====
platform darwin -- Python 2.7.6 -- py-1.4.26 -- pytest-2.6.4
collected 1 items

test/test_project.py F

===== FAILURES =====
_____ test_answer _____

    def test_answer():
>       assert func(3) == 5
E       assert 4 == 5
E        +  where 4 = func(3)

test/test_project.py:5: AssertionError
===== 1 failed in 0.02 seconds =====

The test should fail. Try making the test pass by updating the test_project.py file and running the test again. That brings us to the end of this article. We'll be going over setup.py, unit testing, and python programming in general in follow up articles so check back in the future.

No comments:

Post a Comment