Programming

Navigate files easily with ctrlp.vim

Few years ago I used a lightweight IDE called “Sublime Text 2″. And one of the most compelling features of it was an ability to switch between files by hitting Ctrl + P and typing in a part of the file name.

This is exactly what ctrlp.vim implements in vim. Usage is extremely simple: install the plugin, hit Ctrl + P, type a part of the file name, select a desired file and hit Enter. You can use arrow keys or Ctrl + J and Ctrl + K to navigate between suggested file list.

Source: https://github.com/kien/ctrlp.vim.

Programming

Making Django and Lettuce play nice together

Lettuce is a great BDD tool which allows you to parse expressions written via Gherkin syntax in python. However the documentation is not very comprehensive, and at the moment current version (0.2.19) has some issues integrating with the latest Django (1.6.1 at the moment of writing). Without further ado, I’ll get to a comprehensive tutorial.

Let’s assume you are using pip and virtualenv for the dependency control, and you already have a working project configured. Your project is called “myproject”, and the only app you have within your project is called “polls”.

Setup

First, you have to install lettuce library. At the moment of writing, current released version (0.2.19) has an error integrating with Django, so we’ll install current development version. Releases 0.2.20 and up should include the fix, so pip install lettuce would be better if the version is out.

pip install -e git://github.com/gabrielfalcao/lettuce@cccc397#egg=lettuce-master
pip install django-nose splinter
pip freeze > requirements.txt

First line downloads lettuce package from the github repository and installs missing dependencies. You can replace cccc397 with the current commit. Technically commit can be omitted, but we don’t want to have an unstable ever-changing branch in our requirements.txt. I also added django-nose since nose assertions come in handy while writing Lettuce steps, as well as splinter, which is a great tool for testing web application.

Add Lettuce to the INSTALLED_APPS in your myproject/settings.py:

INSTALLED_APPS = (
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.sites',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'django.contrib.admin',
    'django.contrib.admindocs',
    # ... third party apps ...
    'lettuce.django',
    'myproject',
    'polls',
)

You also have to explicitly specify the apps you want to use with lettuce:

LETTUCE_APPS = (
    'polls',
)

By default, lettuce will run its’ tests against your default database. But we want to use test database for that, so we have to add few more settings:

LETTUCE_TEST_SERVER = 'lettuce.django.server.DjangoServer'
LETTUCE_SERVER_PORT = 9000

Where LETTUCE_TEST_SERVER is a subclass of Django’s LiveTestServerCase – a class which runs a test server for you and LETTUCE_SERVER_PORT is different from port 8000 so you won’t have issues running the development server via python manage.py runserver at the same time as running Lettuce tests.

You also have to create a features directories inside the apps you want to test with Lettuce:

/myproject
    /myproject
        __init__.py
        settings.py
        urls.py
        wsgi.py
    /polls
        /features
            /steps
                __init__.py
                polls_list.py
            polls_list.feature
        __init__.py
        models.py
        tests.py
        views.py
    manage.py
    requirements.txt
    terrain.py

Lettuce has its’ own settings file called terrain.py. It has to be in the same directory as a manage.py:

from django.core.management import call_command
from django.conf import settings
from lettuce import before, after, world
from splinter.browser import Browser

@before.each_scenario
def flush_database(scenario):
    call_command('flush', interactive=False, verbosity=0)

@before.each_scenario
def prepare_browser(scenario):
    world.browser = Browser()

@after.each_scenario
def destroy_browser(scenario):
    world.browser.quit()

This code flushes the database before each scenario, as well as prepares and destroys the splinter browser.

Writing the features

Feature files support standard Gherkin syntax, let’s write one right now in polls/features/polls_list.feature:

Feature: Polls list

    Scenario: Polls list without any polls
        When I access the "polls list" url
        Then I see a text "We didn't find any polls!"

    Scenario: Polls list with one poll
        Given a poll with the title "Hello world"
        When I access the "polls list" url
        Then I see a text "Hello world"
        And I do not see a text "We didn't find any polls!"

Now describe the steps in polls/features/steps/polls_list.py:

from django.core.urlresolvers import reverse
from lettuce import step, world
from lettuce.django import django_url
from nose.tools import assert_in, assert_not_in
from polls.models import Poll

PAGES = {
    "polls list": "polls:list"
}

@step(r'access the "(.*)" url')
def access_the_url(step, name):
    world.browser.visit(django_url(reverse(PAGES[name])))

@step(r'see a text "(.*)"')
def see_a_text(step, text):
    assert_in(text, world.browser.html)

@step(r'a poll with the title "(.*)"')
def create_a_poll_with_the_title(step, title):
    poll = Poll.objects.create(title=title)
    polls.save()

@step(r'do not see a text "(.*)"')
def do_not_see_a_text(step, text):
    assert_not_in(text, world.browser.html)

Running the tests

Now, you can run python manage.py harvest --test-server to run the tests you just wrote:

$ python manage.py harvest --test-server
Creating test database for alias 'default'...
Django's builtin server is running at 0.0.0.0:9000

Feature: Polls list

  Scenario: Polls list without any polls
    When I access the "polls list" url
    Then I see a text "We didn't find any polls!"

  Scenario: Polls list with one poll
    Given a poll with the title "Hello world"
    When I access the "polls list" url
    Then I see a text "Hello world"
    And I do not see a text "We didn't find any polls!"

1 feature (1 passed)
2 scenarios (2 passed)
6 steps (6 passed)
Destroying test database for alias 'default'...

Don’t forget the --test-server switch – otherwise Lettuce will run tests against your default database.

Sources

You can find some more details on Lettuce and Django integration here: Web development fun with Lettuce and Django.

Update

Rather than using `–test-server` switch, it’s easier and safer to set a flag in your `settings.py` (suggested by Michel Sabchuk):

LETTUCE_USE_TEST_DATABASE = True

This way you won’t end up accidentally erasing your production database after forgetting to add `–test-server` flag.

Programming

Open previously edited file in vim

You can open previous location by hitting Ctrl-O. You can prefix the command with a number to go multiple files back. You can also travel forward in “file history” by using Ctrl-I.

There’s a nice article on Vim Wikia with more details on a subject.

Programming

Old file version in split with vim

If you use git VCS, you can view previous version of the file you are currently editing in a split window by executing following command:


:vsp tmp | read !git show HEAD^:path/from/working/directory

For the instant syntax highlighting, you can specify temporary file’s extension, like following:


:vsp tmp.py | read !git show HEAD^:lib/module.py

You can also cycle back by few versions by replacing HEAD^ (which points to the previous commit) with HEAD~N, where N is the number of commits you would like to go back in history by. For example, if you would like to get a version of the file 4 commits ago – you can do so by executing following command:


:vsp tmp | read !git show HEAD~4:path/from/working/directory

It’s a pretty nice hack when you need to quickly view previous version of the file you are working on.

Programming

Pasting with vim and indentation issues

If you use vim often – you probably had to paste something into vim from the outside source. And, if you have corresponding indentation rules, they will get applied, turning your nice block of code into something that looks more like a case of stairs:


def foo(a, b):
        a, b = b, a
            print "I am doing something important."
                return a - b

Quite nasty, isn’t it? But that’s where vim’s paste option comes in. Before pasting, execute :set paste. If you go into insert mode, you’ll see the usual mode indicator switch to -- INSERT (paste) --. Try pasting the same block of code now:


def foo(a, b):
    a, b = b, a
    print "I am doing something important."
    return a - b

Beautiful. Don’t forget to switch back to a regular mode by executing :set nopaste.

Programming

Git crash course (part 1)

Let’s assume you know nothing about git, but for one reason or another you are curious enough to stumble upon this article. This is a zero knowledge required git crash course.

What is git and why do I need it?

Git is a distributed version control system. It keeps track of your code and simplifies collaboration between developers on the same project. Every time you make changes to code, you attach a meaningful message to the set of changes you made, which makes you able to see the history of a project as clearly as this:

* Included documentation in the project (just now)
* Refactored event handler class (7 hours ago)
...
* Initial setup (1 year ago)

With git you are able to see differences between any steps in development, and operate sets of changes on an object level, which makes tracking down errors easier.

Installing git

Git is a command line tool, however it comes with multitude of GUI wrappers. Graphical interface simply invokes git CLI, so we will be not be using GUI.

Head down to the git downloads page, grab and install the version for your platform. After git is installed, open your terminal and test it by running git --version. If it works and you see the output, set up your username and email:

git config --global user.name 'John Doe'
git config --global user.email [email protected]

Now you are ready to start exploring git.

How do I use git?

All the commands here are to be typed in the terminal literally. The “#” symbol is used to indicate a comment.

Let’s assume you have a project with a few files and directories. Let’s create it:

mkdir pets
cd pets
mkdir pet
touch pet/cat.txt pet/dog.txt human.txt
cd ..

Here’s our project:

pet/
pet/cat.txt
pet/dog.txt
human.txt

Creating a repository

First, let’s create a repository – a place where your files and information about the project are stored. It can be on your local machine, or a service like GitHub. For simplicity, you can create a repository on GitHub. Let’s name our repository ‘pets’.

git init  # initialize a repository from existing files
git remote add origin [email protected]:username/pets.git

Now this needs a bit of explanation. The first command initializes a repository, creating a .git/ directory in project root (pets/.git). This directory contains all the information about your project, which you will be operating using git commands. The next command adds a remote repository aliased as “origin”. The word “origin” is a default name for the main remote.

Now, git will keep an eye out for the changes in the pets directory. You can use the status command to see the current directory status:

git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#       human.txt
#       pet/
nothing added to commit but untracked files present (use "git add" to track)

Currently, git has marked our files as “Untracked”, so we need to explicitly tell git to keep track of these files. We do this by using the add command.

git add human.txt pet/
git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#       new file:   human.txt
#       new file:   pet/cat.txt
#       new file:   pet/dog.txt
#

After running git status you can see that all the files we added are marked as “Changes to be committed”. Now git “knows” about the files and is ready to save our progress, which is done by issuing the commit command. Flag -m stands for “message”. Every commit should have a message describing it.

git commit -m "My first initial commit"
# [master (root-commit) 3953648] My first initial commit
#  3 files changed, 0 insertions(+), 0 deletions(-)
#  create mode 100644 human.txt
#  create mode 100644 pet/cat.txt
#  create mode 100644 pet/dog.txt

You just committed your first set of changes! Run a status command:

git status
# On branch master
nothing to commit, working directory clean

The output tells you that all changes to files are accounted for and there are no changes since the last commit. Let’s go over the details of what just happened.

Making changes

Let’s review what we just did:

  • Initializing the repository makes git track changes in the directory. Git operations can only be performed on directories tracked by git.
  • All files in a newly initialized repository are untracked by default, meaning git does not keep a history of changes within the file.
  • In order for git to start tracking changes to a file you need to use the add command. This “stages” file, but the file does not become a part of git history yet.
  • Command commit is used to create a changeset out of staged files. Committed changes become part of the git history.

Your project never stays the same, so let’s assume that now you need to add something to pet/cat.txt. You can edit the file with your favorite text editor, or just echo some text into a file from the command prompt:


echo hello > pet/cat.txt

From what we know so far, the git status command is used to show the current project’s status from the perspective of git. Run it:


git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#  modified:   pet/cat.txt
#
no changes added to commit (use "git add" and/or "git commit -a")

You can see that git detected our changes to pet/cat.txt. The git diff command displays the difference between files – what lines are added, changed, or removed. By default it will compare the current state of your files to the last commit.


git diff
diff --git a/pet/cat.txt b/pet/cat.txt
index e69de29..ce01362 100644
--- a/pet/cat.txt
+++ b/pet/cat.txt
@@ -0,0 +1 @@
+hello

+ before the line means that a string was added and - means it was removed. Differences are also color coded, green for addition and red for removal.

Add and commit your changes:


git add pet/cat.txt
git commit -m "Echo hello to a cat"
[master ba3d31a] Echo hello to a cat
 1 file changed, 1 insertion(+)

Fiddle around and add some more changes and files before proceeding to the next part:


echo goodbye > pet/cat.txt
echo woof > pet/dog.txt
git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#  modified:   pet/cat.txt
#  modified:   pet/dog.txt
#
no changes added to commit (use "git add" and/or "git commit -a")
git diff
diff --git a/pet/cat.txt b/pet/cat.txt
index ce01362..dd7e1c6 100644
--- a/pet/cat.txt
+++ b/pet/cat.txt
@@ -1 +1 @@
-hello
+goodbye
diff --git a/pet/dog.txt b/pet/dog.txt
index e69de29..cfbc74a 100644
--- a/pet/dog.txt
+++ b/pet/dog.txt
@@ -0,0 +1 @@
+woof
git add pet/cat.txt pet/dog.txt
git commit -m "Say goodbye to a cat, say woof to a dog"

Make sure you understand what the status, add, commit, and diff commands are for.

History

You can view a history of all your changes with the git log command. Give it a go:


git log
commit cf0aad6748959edcc0e877335c5b905126802d84
Author: John Doe <[email protected]>
Date:   Thu Oct 10 14:02:59 2013 -0400

    Say goodbye to a cat, say woof to a dog

commit ba3d31a3c9ff2bdbc0e1f60ef96600801ce87355
Author: John Doe <[email protected]>
Date:   Thu Oct 10 13:57:49 2013 -0400

    Echo hello to a cat

commit 5f5db120eb8c189719c477f196ca20ee3316a7cc
Author: John Doe <[email protected]>
Date:   Thu Oct 10 13:49:40 2013 -0400

    My first initial commit

You can look at the state of your files at the time of a specific commit with the checkout command. Use the commit identifier (also called sha1 hash) to retrieve the desired state.


git checkout 5f5db120eb8c189719c477f196ca20ee3316a7cc
Note: checking out '5f5db120eb8c189719c477f196ca20ee3316a7cc'.

You are in 'detached HEAD' state. You can look around, make experimental
changes and commit them, and you can discard any commits you make in this
state without impacting any branches by performing another checkout.

If you want to create a new branch to retain commits you create, you may
do so (now or later) by using -b with the checkout command again. Example:

  git checkout -b new_branch_name

HEAD is now at 5f5db12... My first initial commit

Feel free to jump around and look at your files. To get back to the current state, execute git checkout master (master is the name of your project’s main branch – I’ll get back to this in the next tutorial).

Stand-by for part 2 of this crash course to learn about incorporating git in your daily workflow, the basics of collaboration with other developers, and branching and merging.

Random notes

Remap your Caps Lock

The following three paragraphs are an angry Caps Lock rant. Feel free to skip past it or join me by commenting below.

I’ve had it with Caps Lock! How many times did I accidentally press it while hitting the A key! How many times did I mean Tab or Shift! There is an obvious problem with the Caps Lock placement, and there being only a millimeter of space to designate it from an adjacent key, it is quite difficult to notice when you accidentally press it.

Pushing Caps Lock is more tolerable when typing, but while using keyboard controlled software it’s a real pain; vim turns into a beeping ravaging nightmare, vimperator messes up all your bookmarks… Same thing with websites supporting keyboard shortcuts.

When was the last time I ever used Caps Lock? Over ten years ago, when I was playing a video game that used Caps Lock to switch between running and walking. Em… Seriously? Time to put an end this nonsense.

Linux and Mac

Drop this into your ~/bin/capslockremap, and don’t forget to chmod +x ~/bin/capslockremap. Now run the script with root privileges (that’ll last you until the next restart).


#!/bin/sh

# This temporarily remaps the Caps Lock key to a Control key.
# The keyboard will return to the previous settings after a
# reboot. The Linux console and the X Window system each
# handles keypresses separately, so each must be remapped
# separately. First remap the X keyboard since this does not
# require root access.

# Remap the Caps Lock key to a Control key for
# the X Window system.
if type setxkbmap >/dev/null 2>&1; then
  setxkbmap -layout us -option ctrl:nocaps 2>/dev/null
fi

# You have to be root to remap the console keyboard.
if [ "$(id -u)" != "0" ]; then
  echo "This script is not running as root so"
  echo "the console Caps Lock cannot be remapped."
  echo "Perhaps you forgot to run this under sudo."
  echo "Note that this problem does not effect X."
  echo "This only effects the consoles running on"
  echo "Alt-f1 through Alt-f6."
  exit 2
fi
# Remap the CapsLock key to a Control key for the console.
(dumpkeys | grep keymaps; echo "keycode 58 = Control") | loadkeys

Windows

Download Sysinternals Ctrl2Cap v2.0, run it as Administrator with install flag: ctrl2cap.exe /install.

Source CapsLock Remap Howto – Noah.org.

Space Dev Log

Space v0.3.0-alpha released!

Space reached version v0.3.0-alpha! Interested? Have feedback or want to contribute? Head over to GitHub to join!

space-v0.3.0-alpha-screenshot

Space Dev Log

Space v0.2.0-alpha released!

A recent side project of mine – Space – reached release v0.2.0-alpha. Space is a roguelike multiplayer game, set in the distant future, where players operate spaceships and fight battles in space or on board of spaceships.

space-v0.2.0-alpha-screenshot

You can learn more or join the development efforts on GitHub.

Programming

Python doctests and decorators bug

Now, this as well might be a feature, but doctest strings are not being executed for decorated functions (at least in version 2.7). However, there is a workaround.

You need to decorate your functions with functools.wraps within a decorator to import docstrings into a decorator scope.

#!/usr/bin/env python

from functools import wraps

def decorator(func):
    @wraps(func)
    def wrapper():
        return func()
    return wrapper

@decorator
def foo():
    """
    >>> foo()
    False
    """
    return True

import doctest
doctest.testmod()

Now you can see this test failing, where otherwise it would have been ignored:

**********************************************************************
File "decorator.py", line 12, in __main__.foo
Failed example:
    foo()
Expected:
    False
Got:
    True
**********************************************************************
1 items had failures:
   1 of   1 in __main__.foo
***Test Failed*** 1 failures.