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.
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
.
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
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.
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.
Python tests with doctest and unittest
When it comes to tests, doctest
is a great simple module to write tests for
your application. However it is pretty basic and does not have any extended
features like, for example, centralized unit tests. If you have multiple
modules with doctests (and you probably do) you most likely want to be able to
run all doctests recursively from one place. That’s where unittest
comes in.
Let’s assume we store modules in the lib/
directory:
$ ls lib/
__init__.py bar.py foo.py
Here are the contents of foo.py
and bar.py
respectfully:
def foo():
"""
>>> foo()
False
"""
return False
def bar():
"""
>>> bar()
True
"""
return True
def baz():
"""
>>> baz()
False
"""
return False
Now, to run all tests we need a wrapper script. Let’s call it: runtests.py
:
#!/usr/bin/env python
import unittest
import doctest
import os
files = []
root_dir = 'lib/'
for root, _, filenames in os.walk(root_dir):
for filename in filenames:
if filename == '__init__.py' or filename[-3:] != '.py':
continue
f = os.path.join(root, filename)
f = f.replace('/', '.')
f = f[:-3]
files.append(f)
suite = unittest.TestSuite()
for module in files:
suite.addTest(doctest.DocTestSuite(module))
unittest.TextTestRunner(verbosity=1).run(suite)
This approach invokes the doctest.DocTestSuite
method, which converts
doctests strings into unittest suites. Time to run our tests:
$ chmod +x runtests.py
$ ./runtests.py
...
----------------------------------------------------------------------
Ran 3 tests in 0.008s
OK
And just to be sure that approach actually works, let’s make one of the tests fail:
$ ./runtests.py
.F.
======================================================================
FAIL: baz (lib.bar)
Doctest: lib.bar.baz
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python2.7/doctest.py", line 2201, in runTest
raise self.failureException(self.format_failure(new.getvalue()))
AssertionError: Failed doctest test for lib.bar.baz
File "/home/rosipov/unitdoc/lib/bar.py", line 8, in baz
----------------------------------------------------------------------
File "/home/rosipov/unitdoc/lib/bar.py", line 10, in lib.bar.baz
Failed example:
baz()
Expected:
True
Got:
False
----------------------------------------------------------------------
Ran 3 tests in 0.009s
FAILED (failures=1)