Working with File Paths in Python Using pathlib

Uploaded documents flowing through connected folders into a portable application destination path

What You’ll Learn

In this lesson, you will learn how to use Python’s pathlib module to work with file-system paths in a portable way. Instead of manually joining strings with / or \, you will build paths that work across operating systems.

  • Create a Path object.
  • Join folders and filenames with the / operator.
  • Inspect filenames, extensions, and parent folders.
  • Use paths in a simple uploaded-file workflow.

The Concept

A file path tells your program where a file or folder is located. For example, an uploaded file might need to be stored in an uploads folder inside your application.

Many beginners build paths by joining strings:

"app_data/" + "uploads/" + filename

This can cause problems because different operating systems use different path separators. Windows commonly uses backslashes, while Linux and macOS commonly use forward slashes.

Python’s pathlib module provides the Path class for working with paths. The / operator joins path parts correctly for the operating system running your program.

A Path object represents a location. It does not necessarily mean that the file or folder already exists. You can use methods and properties such as .exists(), .name, .suffix, and .parent to inspect that location.

Basic Example

Suppose an application receives an uploaded file named profile-photo.png. We can build the destination path without manually writing operating-system-specific separators.

from pathlib import Path

application_folder = Path("file_processor")
upload_folder = application_folder / "uploads"
uploaded_filename = "profile-photo.png"
uploaded_file_path = upload_folder / uploaded_filename

print("Upload folder:", upload_folder)
print("File path:", uploaded_file_path)
print("Filename:", uploaded_file_path.name)
print("Extension:", uploaded_file_path.suffix)
print("Parent folder:", uploaded_file_path.parent)

Expected Output

The displayed path separator can vary by operating system. The following output shows the common Unix-style form:

Upload folder: file_processor/uploads
File path: file_processor/uploads/profile-photo.png
Filename: profile-photo.png
Extension: .png
Parent folder: file_processor/uploads

How the Code Works

A process diagram showing an uploaded filename converted to a clean final name, joined to a portable upload folder with pathlib, checked for an allowed extension, and routed either to folder creation and a ready destination path or rejection.
Using pathlib, clean and validate an uploaded filename, build a portable destination path, and create its parent folders before saving.

from pathlib import Path imports the Path class. This class gives you useful operations for creating and inspecting paths.

This line creates a path for the main application folder:

application_folder = Path("file_processor")

The path is relative, which means it starts from the program’s current working directory. It does not create the folder by itself.

Next, the / operator joins the application folder and the uploads folder:

upload_folder = application_folder / "uploads"

With pathlib, this is path joining, not ordinary division. Python chooses the correct separator for the operating system.

The filename is then joined to the upload folder:

uploaded_file_path = upload_folder / uploaded_filename

The result is a Path object. Important Path properties include:

  • .name returns the final filename.
  • .suffix returns the file extension, including the dot.
  • .parent returns the folder containing the path.
  • .exists() checks whether the path currently exists.

For example, if you need to create the upload folder before saving a file, use mkdir():

upload_folder.mkdir(parents=True, exist_ok=True)

parents=True allows Python to create missing parent folders, such as file_processor. exist_ok=True prevents an error if the folder already exists.

Another Example

Uploaded filenames can sometimes contain directory information, such as temporary/photo.jpg. If your application only needs the final filename, Path(...).name can extract it before building the destination path.

This example also checks the file extension before accepting the upload. It does not save the file; it prepares and inspects the destination path.

from pathlib import Path

def prepare_image_upload(upload_folder, original_name):
    original_path = Path(original_name)
    clean_filename = original_path.name
    destination = upload_folder / clean_filename

    if destination.suffix.lower() not in {".jpg", ".jpeg", ".png"}:
        return None

    return destination


image_upload_folder = Path("file_processor") / "images"
destination_path = prepare_image_upload(
    image_upload_folder,
    "temporary/profile-photo.JPG"
)

if destination_path is None:
    print("Unsupported image type.")
else:
    print("Ready to save:", destination_path)
    print("Stored filename:", destination_path.name)

The function returns a Path when the extension is accepted. Calling .suffix.lower() means that .JPG and .jpg are treated the same way.

Extracting the final name is useful when you want to prevent an uploaded name from adding unexpected folders to your destination path. In a real application, you should also consider filename collisions and validate uploads according to your application’s security requirements.

Common Mistakes

  • Joining paths with string concatenation: Avoid expressions such as folder + "/" + filename. Use Path(folder) / filename instead.
  • Assuming a Path creates something: Building a path only creates a Python object. Use mkdir() to create a directory or an appropriate file-writing operation to create a file.
  • Using .suffix as the complete filename: For report.final.pdf, .suffix is ".pdf", while .name is "report.final.pdf".
  • Forgetting that relative paths depend on the current directory: Path("uploads") refers to an uploads folder under wherever the program was started. Use an absolute base path when your application requires a fixed location.
  • Trusting uploaded names without inspection: Use Path(uploaded_name).name when you need only the final name, and apply suitable validation before storing user-provided files.

Try It Yourself

Create a path for a text upload inside file_processor/text_uploads. Then print its filename, extension, and parent folder.

Start with this code and complete the missing lines:

from pathlib import Path

text_upload_folder = Path("file_processor") / "text_uploads"
uploaded_name = "meeting-notes.txt"
text_file_path = text_upload_folder / uploaded_name

print("Filename:", text_file_path.name)
print("Extension:", text_file_path.suffix)
print("Parent folder:", text_file_path.parent)

Challenge

Write a function named prepare_upload_path that prepares a destination path for an uploaded file.

  • Accept an upload folder and an original filename as parameters.
  • Keep only the final filename by using .name.
  • Return None for files that do not end in .pdf or .txt, ignoring letter case.
  • Return the destination Path for accepted files.
  • Use the function with "incoming/notes/quarterly-report.PDF" and print the resulting path.

Solution

from pathlib import Path

def prepare_upload_path(upload_folder, original_name):
    original_path = Path(original_name)
    clean_filename = original_path.name
    destination = upload_folder / clean_filename

    if destination.suffix.lower() not in {".pdf", ".txt"}:
        return None

    return destination


upload_folder = Path("file_processor") / "documents"
destination_path = prepare_upload_path(
    upload_folder,
    "incoming/notes/quarterly-report.PDF"
)

if destination_path is None:
    print("Unsupported file type.")
else:
    print("Ready to save:", destination_path)

The function converts the incoming name to a Path, extracts only its final component, and joins that filename to the application’s document folder. The lowercase suffix check accepts the uppercase .PDF extension while still limiting the allowed types.

Key Takeaways

  • Use Path to represent file and folder locations in Python.
  • Join path parts with the / operator instead of manually writing separators.
  • Use properties such as .name, .suffix, and .parent to inspect paths.
  • Use mkdir(parents=True, exist_ok=True) when an upload directory needs to be created.
  • Inspect and validate uploaded filenames before using them in a file-storage workflow.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top