-
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
pipandvirtualenvfor 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
lettucelibrary. 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, sopip install lettucewould 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.txtFirst line downloads lettuce package from the github repository and installs missing dependencies. You can replace
cccc397with the current commit. Technically commit can be omitted, but we donāt want to have an unstable ever-changing branch in ourrequirements.txt. I also addeddjango-nosesince nose assertions come in handy while writing Lettuce steps, as well assplinter, which is a great tool for testing web application.Add Lettuce to the
INSTALLED_APPSin yourmyproject/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 = 9000Where
LETTUCE_TEST_SERVERis a subclass of DjangoāsLiveTestServerCase- a class which runs a test server for you andLETTUCE_SERVER_PORTis different from port 8000 so you wonāt have issues running the development server viapython manage.py runserverat the same time as running Lettuce tests.You also have to create a
featuresdirectories 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.pyLettuce has itsā own settings file called
terrain.py. It has to be in the same directory as amanage.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
splinterbrowser.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-serverto 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-serverswitch - 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-serverswitch, itās easier and safer to set a flag in yoursettings.py(suggested by Michel Sabchuk):LETTUCE_USE_TEST_DATABASE = TrueThis way you wonāt end up accidentally erasing your production database after forgetting to add
--test-serverflag. -
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 usingCtrl-I.Thereās a nice article on Vim Wikia with more details on a subject.
-
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/directoryFor the instant syntax highlighting, you can specify temporary fileās extension, like following:
:vsp tmp.py | read !git show HEAD^:lib/module.pyYou can also cycle back by few versions by replacing
HEAD^(which points to the previous commit) withHEAD~N, whereNis 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/directoryItās a pretty nice hack when you need to quickly view previous version of the file you are working on.
-
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 - bQuite nasty, isnāt it? But thatās where vimās
pasteoption 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 - bBeautiful. Donāt forget to switch back to a regular mode by executing
:set nopaste. -
Remap your Caps Lock
The following three paragraphs are an angry
Caps Lockrant. 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 theAkey! How many times did I meanTaborShift! There is an obvious problem with theCaps Lockplacement, 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 Lockis more tolerable when typing, but while using keyboard controlled software itās a real pain;vimturns into a beeping ravaging nightmare,vimperatormesses 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 usedCaps Lockto 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 tochmod +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 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") | loadkeysWindows
Download Sysinternals Ctrl2Cap v2.0, run it as Administrator with
installflag:ctrl2cap.exe /install.Source CapsLock Remap Howto - Noah.org.