Explain Codes LogoExplain Codes Logo

How do I create a directory, and any missing parent directories?

python
pathlib
file-exists-error
race-conditions
Nikita BarsukovbyNikita Barsukov·Sep 8, 2024
TLDR

The most direct method for creating a directory, along with any occurring parent directories, involves using os.makedirs() with exist_ok=True:

import os # Even if the directory already exists, Python don't care, it's cool like that! os.makedirs('your/directory/path', exist_ok=True)

This syntax also works perfectly well with Python versions 3.5 and onward, through the use of pathlib.Path.mkdir():

from pathlib import Path # Python 3.5 asks why use os when you can Path your way to glory? Path('your/directory/path').mkdir(parents=True, exist_ok=True)

Python Version Specific Solutions: Choose Your Fighter

Compatibility issues across different Python versions are common. Here's how to tackle them efficiently:

Python 2.7 and Its Love for the Old Ways:

import os try: os.makedirs('your/directory/path') except OSError as e: if e.errno != errno.EEXIST: # Too old to handle `exist_ok`, needs manual error handling 🧓 raise

Python 3.2 - 3.4 Going Modern, but Not Quite There Yet:

import os # `exist_ok` came along for the easy ride 😎 os.makedirs('your/directory/path', exist_ok=True)

Python 3.5+ The Golden Age of Python:

from pathlib import Path # The Zen of Python: "Now is better than never." Make directories now, worry never! Path('your/directory/path').mkdir(parents=True, exist_ok=True)

Error and Exception Handling: Taming the Python

FileExistsError: Huh! I Already Live Here! - Directories

Python versions 3.3 and newer enjoy the luxury of FileExistsError to handle the case where a directory already exists:

try: os.makedirs('dirname') except FileExistsError: # "There can be only One!" - Highlander pass

Race conditions: The One Who Guards the Path

When checking a directory's existence before creating it, another process might create or delete it. This fun scenario is called race conditions. There's nothing like a good race to wake up in the morning!

if not os.path.exists('dirname'): os.makedirs('dirname') # Might not win this race, other processes are cheating 🏁

Directory and File Conflicts: When Namesake Creates Confusion

One might often stumble upon naming conflicts with existing files. Two items, one name? Not on my watch? Use os.path.isdir() instead of os.path.exists() to specifically target directories:

if not os.path.isdir('dirname') and not os.path.exists('dirname'): os.makedirs('dirname') # Like twins at a party, need to know who is who 🥳

Permission errors: Knocking on Heaven's Door

Sometimes, you might try entering (creating, in our case) a directory, and someone yells, "Invalid permissions." An OSError and a code errno.EACCES break the news to you!

try: os.makedirs('dirname') except OSError as e: if e.errno == errno.EACCES: # It's a private property, no trespassing! print("Permission denied.") else: # If ArgumentException, it's beyond our Python's comprehension raise

pathlib: Python's Swiss Army Knife for Paths

pathlib represents filesystem paths while accommodating different operating systems' functionalities. Introduced in Python 3.4, pathlib is both elegant and efficient:

Accessing Parent Directories: Where Art Thou?

from pathlib import Path p = Path('/the/path/you/want/to/create') # pathlib knows its way up 👆 p.parent.mkdir(parents=True, exist_ok=True)

Older Pythons Can Benefit from pathlib Too! Time Travel, Anyone?

The pathlib2 backport package grants the privilege of using pathlib's simplicity and efficiency, even with older Python versions:

from pathlib2 import Path # Python 2 just went under plastic surgery and now looks like Python 3! Path('your/directory/path').mkdir(parents=True, exist_ok=True)

Pathlib for Relative Paths: Don't Lose Yourself

pathlib makes it a cakewalk to work with relative paths:

from pathlib import Path p = Path('./relative/directory/path') # Why go far, when you can make a difference right here? p.mkdir(parents=True, exist_ok=True)

pathlib methods chain together intuitively, aligning with Python’s philosophy of readability and simplicity.