Aug 262011
 

Recently, while trying to resolve a bug in Bcfg2, I ran into a situation which can be summed up by the following:

Python 2.7.1 (r271:86832, Mar 26 2011, 11:26:21)
[GCC 4.4.5] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import os, stat
>>> dev = os.makedev(1, 3)
>>> mode = stat.S_IFCHR | 0777
>>> print(mode)
8703
>>> os.mknod('test', mode, dev)
>>> os.stat('test')
posix.stat_result(st_mode=8685, st_ino=1148358, st_dev=12L, st_nlink=1, st_uid=0, st_gid=0, st_size=0, st_atime=1314372451, st_mtime=1314372451, st_ctime=1314372451)

Above, you can see that the mode specified ends up being different than the mode which is set by os.mknod. Instead of a character device with permissions of 0777, I was ending up with permissions of 0755. If you follow the link, you will find no documentation mentioning the umask of the running process in the mknod section. However, you can search around the page and realize that the umask of the running process is masked out for other methods.

The inconsistency arises due to the implementation of mknod used by Python. For instance, if you run the above code on Windows under Cygwin, it does the Right Thing ™. This was my clue that there was something about the implementation that was off. Sure enough, after committing a simple fix, the problem disappeared.

I think this is simply a documentation issue, but I was unable to find any information on the problem while searching around. Hopefully this post will save someone from wasting a ton of time on the same issue.

 Posted by at 20:05
Sep 142010
 

I was recently converting a bash script to python. I had a need to grab the last item (and only the last item) off the end of a list in order to implement bash’s basename function since Python’s basename function is not quite the same. The bash script had a line like the following

tmpbase=`basename $0`

I was able to get the information I needed by using the __file__ attribute in the script itself. From this, I was able to split the full pathname like this:

solj@abbysplaything $ cat foo.py
#!/usr/bin/env python3
print(__file__.split('/'))

solj@abbysplaything $ python /home/solj/foo.py
['', 'home', 'solj', 'foo.py']

As you can tell, the length of this path could vary depending on where the user runs the script from. Therefore, I needed to grab the first item from the end of the list in order to properly emulate the basename function of bash. I ended up being able to do the following:

tmpbase = __file__.split('/')[-1:]

The negative index allows you to count from the end of the list (I love Python). However, as it turns out, I am blind and didn’t finish fully reading the os.path documentation. This particular problem was solved in a much more elegant way using os.path.split() although I find the negative index to be an extremely useful thing to know.

 Posted by at 19:04