I’m going to tell you a little story about a bug. Like most bugs, it started with an invalid assumption. You see, I was ambushed by permissions on a network file system. Here’s what my code looked like, at least in spirit:
import os import os.path # Build a path filepath = 'relative/path/to/file.txt' dirpath = os.path.dirname(filepath) # Create the directories in the path os.makedirs(dirpath) print("Success")
Go head and try that. Let me know how it works for you. It works fine for me. Well, it usually works fine for me. It could fail if I don’t have permission to create a directory in the current directory. Let’s add a test:
import os import os.path # Build a path filepath = 'relative/path/to/file.txt' dirpath = os.path.dirname(filepath) # Create the directories in the path if os.access('.', os.W_OK): os.makedirs(dirpath) print("Success") else: print("No write permission for current directory")
It seems to work:
troy$ chmod 555 . troy$ python demonstration2.py No write permission for current directory troy$ ls -l total 96 -rw-r--r-- 1 troy staff 194 Apr 27 11:20 demonstration1.py -rw-r--r-- 1 troy staff 290 Apr 27 11:21 demonstration2.py troy$ chmod 755 . troy$ python demonstration2.py Success troy$ ls -l total 96 -rw-r--r-- 1 troy staff 194 Apr 27 11:20 demonstration1.py -rw-r--r-- 1 troy staff 290 Apr 27 11:21 demonstration2.py drwxr-xr-x 3 troy staff 102 Apr 27 11:22 relative
Stepping back from the task at hand, let me mention that software developers rarely have great control over the execution environment. Let’s look at what happened to me when a user ran my directory creation code:
troy$ python path/to/demonstration2.py Traceback (most recent call last): File "path/to/demonstration2.py", line 10, in <module> os.makedirs(dirpath) File "path/to/lib/python2.7/os.py", line 150, in makedirs makedirs(head, mode) File "path/to/lib/python2.7/os.py", line 157, in makedirs mkdir(name, mode) OSError: [Errno 13] Permission denied: 'relative/path'
That’s not what I had expected. I had the user run some commands:
user$ mkdir directory user$ touch file user$ mkdir directory/child mkdir: directory/child: Permission denied user$ ls -l total 32 drwxr-xr-x 2 user staff 16384 Apr 27 11:30 directory -rw-r--r--@ 1 user staff 0 Apr 27 11:30 file
The user was able to create directories and files, but not subdirectories. This seems peculiar. While I knew that the user intended to use my code on a network file system, I hadn’t considered that directory creation would fail—especially not after creating the first directory successfully.
The source of this particular issue was in the configuration of the file server. The OS X file server can be configured allow creation of directories but not child files or directories. It can even be configured to create directories and files with specific permissions, ignoring the mode passed to calls like
I was reminded of a few things from this:
- Code defensively. You know that function calls can fail. Handle the errors. (At least log or report them.)
- Your file system may not always cooperate with the OS-level function calls.
- This is especially true when you are not in control of the execution environment.