apple bash computing original-content osx python scripting
by Layne
leave a comment
Python version of seq for OSX
OSX is based on BSD, so it is missing some of the standard GNU utilities we’ve come to expect on a linux-y system. The most frequently used of these missing utilities is the seq utility, which is used to define a range of numbers, very useful in quick loops from the command line:
$ seq 6 12
6
7
8
9
10
11
12
You can also use the -w flag to get zero-padded output:
$ seq -w 6 12
06
07
08
09
10
11
12
The nearest BSD equivalent is something called jot which of course has more functionality but is not compatible with good old seq. I wrote a quick and dirty python script to emulate the simple behaviors of seq, specifically the base counting behavior and the -w behavior. Put it somewhere on your path (I’d suggest ~/bin/) and you should be good to go:
#!/usr/bin/env python
import sys, math
if len(sys.argv) < 3:
print "Usage: %s [-w] min max" % sys.argv[0]
sys.exit(1)
try:
if len(sys.argv) == 4:
wide = True
min = int(sys.argv[2])
max = int(sys.argv[3])
else:
wide = False
min = int(sys.argv[1])
max = int(sys.argv[2])
except:
print "Error: min and max must be integers"
sys.exit(1)
width = int(math.ceil(math.log10(max)))
for i in range(min, max + 1):
if wide:
print "%0*d" % (width, i)
else:
print "%d" % i
Update LXML on OS X
The Python scripting language is used for many extentions, add-ons and filters in the Inkscape vector graphics application. Unfortunately, Mac OS X doesn’t ship with very recent versions of some commonly used Python libraries, most notably an XML and HTML processing library called LXML. To install a more recent version, you can issue this command from the terminal:
sudo easy_install lxml
Using command line arguments in Python in IDLE.
I’m not a big fan of integrated development environments (IDEs), but they can be nice to help people get introduced to a new language, or even to programming in general. Processing and Arduino wouldn’t be as easy for new people to use if they didn’t have a decent IDE.
Most useful scripts accept command line arguments to configure their behavior, but sometimes it is difficult to set command line parameters from within an IDE. I was recently working on a python project with a friend living in Florida, new to the world of programming, so I showed him how to use Python’s IDLE interface, a nice IDE for Python work. Unfortunately, there is no way to set command line arguments from IDLE, so our scripts weren’t working in the IDE. I found a way to manually set the command line arguments if a Python script is run from IDLE, but doesn’t interfere if the script is run from the console.
To use, insert this code right after the start of your main-line code, right before you do your parsing and validation of the input parameters. Be sure that the specified arguments below match what your program is expecting.
try:
__file__
except:
sys.argv = [sys.argv[0], 'argument1', 'argument2', 'argument2']
Scons – A cross-platform, Python-based build system
In other work news, I was introduced to the scons build system, since we do a lot of cross-platform development at my job. Python is of course cross-platform, and the powers that be decided that this would be a good way to go.
Everyone who has struggled with makefiles in the past will love the simplicity and ease of use that comes with scons. A scons build file, normally called SConstruct, can be as simple as:
Program('hello.c')
What’s special about scons, is that the SConstruct file is also a python script, so you can use all the nice python syntax for things such as list concatenation, as in the following example that builds two programs that share a few common source files:
common = ['common1.c', 'common2.c']
foo_files = ['foo.c'] + common
bar_files = ['bar1.c', 'bar2.c'] + common
Program('foo', foo_files)
Program('bar', bar_files)
In large projects, the source files are naturally split into independently-buildable modules in different directories. When you try to use Make to manage this sort of hierarchal build layout, it’s usually maddening due to the reliance on environment variables and other things. With scons, you simply “conscript” the other scripts to build their part of the project:
SConscript(['drivers/SConscript',
'parser/SConscript',
'utilities/SConscript'])
Overall, scons is a pretty awesome piece of software, and I’ll hopefully be using it in the future for projects of my own.
Find duplicate directories with Duplicate Directory Hunter
Duplicate Directory Hunter is a python script I wrote to help find duplicate directories quickly. While I’ve always been obsessive about backups, I’ve been less than perfect about maintaining their organization, or doing them the right way. Often times, I would just copy directory trees into a archive folder, or rename the copied folder whatever.old.
At one point, I estimated I had over 200 gigs of redundant backups. Having extra backups like this certainly hinders my efforts at offsite backup. While I can compare directory trees and files with diff, this takes a long time per directory, and I have to give it a pair of roots to compare. What if I don’t know which directories to compare?
Adam Wolf’s Feels Like Burning » Duplicate Directory Hunter released!
Python Doctest Example
def factorial(n):
"""Return the factorial of n, an exact integer >= 0.
If the result is small enough to fit in an int, return an int.
Else return a long.
>>> [factorial(n) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> [factorial(long(n)) for n in range(6)]
[1, 1, 2, 6, 24, 120]
>>> factorial(30)
265252859812191058636308480000000L
>>> factorial(30L)
265252859812191058636308480000000L
>>> factorial(-1)
Traceback (most recent call last):
...
ValueError: n must be >= 0
Factorials of floats are OK, but the float must be an exact integer:
>>> factorial(30.1)
Traceback (most recent call last):
...
ValueError: n must be exact integer
>>> factorial(30.0)
265252859812191058636308480000000L
It must also not be ridiculously large:
>>> factorial(1e100)
Traceback (most recent call last):
...
OverflowError: n too large
"""
import math
if not n >= 0:
raise ValueError("n must be >= 0")
if math.floor(n) != n:
raise ValueError("n must be exact integer")
if n+1 == n: # catch a value like 1e300
raise OverflowError("n too large")
result = 1
factor = 2
while factor <= n:
result *= factor
factor += 1
return result
def _test():
import doctest
doctest.testmod()
if __name__ == "__main__":
_test()
[via doctest documentation]