Skip to Content
Course content

93: Working with File Paths Portably

Click on the "Edit" button in the top corner of the screen to edit your slide content.

I can't tell you how many times I've received a bug report that simply said, "The script crashes on startup," only to realize the user was on Windows and I'd written the code on a Mac. The culprit is almost always the slash. Windows likes backslashes (\); Unix-based systems (Linux, macOS) use forward slashes (/). If you hardcode these into your strings, your code is essentially a ticking time bomb for anyone using a different OS.

The hardcoded trap

Let's say we're building a small utility that reads a configuration file from a config folder and writes a session log to a logs folder. My first instinct—and I'll admit I still do this when I'm rushing—is to just write the path as a string. Check this out:

# My initial (flawed) approach
log_path = "logs/session.log"
with open(log_path, "w") as f:
    f.write("Session started")

This works perfectly on my MacBook. But the moment I send this to a colleague on Windows, they might hit an FileNotFoundError or a permissions issue because the OS is expecting a different path separator. Even if Python's open() function is smart enough to handle forward slashes on Windows most of the time, relying on that is a bad habit. It falls apart the second you start interacting with system shells or external APIs.

Switching to the Pathlib way

Years ago, we used os.path.join(). It worked, but it was clunky and felt like writing a math equation just to find a file. Now, we have pathlib. It treats paths as objects rather than strings, which is a total game-changer.

Here is how I'd actually rewrite that log manager to be truly portable:

from pathlib import Path

# Create a Path object for the current directory
base_dir = Path(".") 

# We use the / operator! 
# Pathlib overloads this to join paths regardless of the OS.
log_folder = base_dir / "logs"
log_file = log_folder / "session.log"

# Make sure the directory actually exists first
log_folder.mkdir(exist_ok=True)

log_file.write_text("Session started")
print(f"Log written to: {log_file}")

The / operator here isn't doing division; pathlib has hijacked it to mean "append this to the path." If you're on Windows, it knows to use \ under the hood. If you're on Linux, it uses /. You don't have to think about it, which is exactly where you want to be.

Avoiding the "Current Working Directory" headache

There's one more trap. In the example above, I used Path("."). That refers to the current working directory—which is wherever the user happened to be in their terminal when they ran the script. If they are in their home folder but the script is in /projects/my_app/, Path(".") will look in the home folder and fail to find your config files.

To fix this, I always anchor my paths to the location of the script itself using __file__. This ensures the script always knows where its own folders are, no matter where it's called from:

from pathlib import Path

# This gets the absolute path to the directory where this script lives
SCRIPT_DIR = Path(__file__).resolve().parent

# Now we define paths relative to the script location
CONFIG_FILE = SCRIPT_DIR / "config" / "settings.ini"
LOG_DIR = SCRIPT_DIR / "logs"

print(f"Looking for config at: {CONFIG_FILE}")

By using .resolve().parent, we've made the script completely independent of the user's terminal state. It's a small detail, but it's the difference between a script that "mostly works" and professional-grade software.




📋 Practical Task

Build a Portable Project Directory Initializer

Your task is to create a script that sets up a project folder structure automatically. The script must be portable and should not rely on the user's current working directory.

Write a script that does the following:

  • Determines the directory where the script is located using __file__.
  • Creates three folders relative to that location: data, exports, and temp.
  • Inside the data folder, creates an empty file named database.csv.
  • Inside the exports folder, creates an empty file named report.pdf.
  • Prints the absolute path of the report.pdf file to the console to verify it was created in the right place.

Constraint: You must use pathlib.Path for all path manipulations. Do not use string concatenation or os.path.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.