LESSON 29 · DEEPER PYTHON27 min

Work with File Paths using pathlib

Build and inspect paths with pathlib, create missing parent folders, and read or write UTF-8 text safely.

Video lesson: Work with File Paths using pathlib

The preview is stored on this site. YouTube loads only when you press Play. Watch on YouTube

Read the video transcript

Select a timestamp to watch that moment on YouTube.

  1. 00:00

    We want to save a short note in a nested folder. The file name is lesson-note.txt, but the whole path includes two folders before it. A beginner might expect that asking Python to write the file will also create those folders. It does not. In this video we will run that failing write, inspect which part of the path is missing, then create the parent directories deliberately. We will use pathlib, the standard-library API that represents a path as an object instead of building one long string by hand. The companion lesson has a browser Python console, a checked task, and examples you can edit.

  2. 00:40

    In that console, files live in the temporary browser Python filesystem; they do not appear on your computer's disk. The same pathlib methods work for local scripts, but the location of a relative path depends on where the program runs. That is why a path can look correct and still refer to a different place than you expected. Before the terminal run, predict whether the file or its parents already exist. Keeping those two questions separate is the key to diagnosing this failure. The write failed before a file was created. The error name can feel surprising because we were trying to create a new file. The missing part is actually a parent directory. `write_text` can create or replace the file at its path when that file's parent already exists, but it does not create a chain of folders.

  3. 01:30

    We caught the exception so the demonstration can continue; we should not silently ignore it in a real save function. The path object still exists as a Python value even though the path it describes does not yet exist on the filesystem. A Path is a description and a collection of operations, not proof that a file is present. This distinction also applies when reading. Constructing `Path('report.txt')` succeeds even if there is no report. The failure appears when an operation needs the actual file or directory. The right response is to inspect the path's parent and decide whether creating it is part of our function's job.

  4. 02:11

    For this teaching task, it is. `name` is only the final file name. `parent` is the folder that must exist before the write. `exists` is false in this fresh run, confirming the missing piece. `is_absolute` is false, so the path is interpreted relative to the current working directory. If a real program says a file is missing even though you can see it elsewhere, inspect `Path.cwd()` and compare it with where the file actually lives. A script's working directory is determined by how you launch it, not necessarily by the folder holding the script. Avoid guessing by changing random `../` prefixes until something runs.

  5. 02:53

    Diagnose the location, then choose an explicit base path. pathlib uses the platform's path separators when it displays a Path. Your output may show backslashes on Windows and forward slashes in the browser's Python runtime. The logical parent and name are the same. We deliberately keep the example relative so it can run in a temporary workspace without touching personal files. `path.parent.mkdir` creates the parent folder. `parents=True` lets it create both missing levels. `exist_ok=True` lets the same code run again when those folders already exist. We then write the note as UTF-8 text and read it back with the same encoding.

  6. 03:37

    Reading back gives us an observable check that the write happened at the path we intended. The function returns a value instead of printing inside; a caller can display that value or use it in a test. pathlib's slash operator can join path parts, such as `Path('pll-demo-notes') / 'unit-1' / 'lesson-note.txt'`, without manually inserting the platform's separator. We accept a path string here because the lesson's task asks for one, then convert it at the boundary. Remember that this simple function overwrites an existing file. If preserving the previous contents matters, define that rule before writing.

  7. 04:17

    Likewise, an application accepting arbitrary user paths would need to decide where files are allowed. The exercise uses controlled local paths so we can focus on the core path operations. The second call uses an existing parent folder, so `exist_ok=True` matters. The accented text survives both write and read because we specified UTF-8. The returned name contains only the final component, not the whole path. In the website task, start with the flat file path from the starter code, then test a nested path. The checker uses both, so skipping parent creation may appear to work for the flat case and fail on the nested one.

  8. 05:00

    When you finish the task and quiz, try a small extension: accept a Path object as well as a string and return the absolute path for display. Predict how a relative path will change when you run the same script from a different working directory. A reliable file program makes its base directory and overwrite behavior explicit. pathlib gives you clear operations for those choices, but the program still has to define them.

Understand the concept

A path identifies a file or folder. Joining path parts with / is clearer and more portable than inserting separators into strings. Path('notes') / 'today.txt' builds a path object; its .name, .stem, .suffix, and .parent expose parts without brittle slicing. A relative path is interpreted from the current working directory, which may differ from the script's location.

Path.write_text(text, encoding='utf-8') opens a file, writes text, and closes it. Path.read_text(encoding='utf-8') reads it back. Like opening a file in 'w' mode, write_text replaces existing contents. When the parent folder does not yet exist, the write fails with FileNotFoundError. Create it first with path.parent.mkdir(parents=True, exist_ok=True).

PurePosixPath lets you reason about forward-slash paths without touching a filesystem, and its output is the same on Windows and Linux. Use a concrete Path when you actually need to create or read a file on the current system. In the browser lesson, those files live in the Python runtime's temporary filesystem, not in a permanent folder on your computer.

The exercise receives both a path and a note. It should create any missing parent folders, write the note as UTF-8, read it back, and return a label containing only the filename and the saved content. Test a flat filename, a nested path, Unicode text, and overwriting an existing note.

  • Path joins parts with /
  • name, stem, suffix, and parent describe a path
  • mkdir(parents=True, exist_ok=True) creates missing folders
  • write_text replaces existing text

See it step by step

Read the code, predict the output, then compare it with the result.

01. Inspect a path without opening a file

PYTHON
from pathlib import PurePosixPath

path = PurePosixPath("reports/2026/summary.csv")
print(path.name)
print(path.stem, path.suffix)
print(path.parent.as_posix())
EXPECTED OUTPUT
summary.csv
summary .csv
reports/2026

PurePosixPath parses the path text. name includes the extension, stem removes it, and parent is the containing path.

02. Write, read, and remove a temporary note

PYTHON
from pathlib import Path

path = Path("pll-demo-note.txt")
path.write_text("draft", encoding="utf-8")
print(path.read_text(encoding="utf-8"))
path.unlink()
EXPECTED OUTPUT
draft

write_text and read_text handle opening and closing. unlink removes this short-lived demonstration file.

03. Create a nested file in a temporary folder

PYTHON
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as root:
    path = Path(root) / "notes" / "today.txt"
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text("hello", encoding="utf-8")
    print(path.name, path.read_text(encoding="utf-8"))
EXPECTED OUTPUT
today.txt hello

The parent folder must exist before the write. TemporaryDirectory removes this example's folder when the block ends.

A closer look

Follow the reasoning, inspect each result, then try the suggested changes in the console below.

01 / 03

Build a path from pieces

pathlib.Path represents a filesystem path as an object rather than a string you manually join with slashes. The / operator combines a directory with a filename using the current environment's path rules. A path can be inspected before any file exists: name is the last part, stem is the filename without its final suffix, and suffix is that final extension. These attributes are useful for choosing an output filename or filtering incoming files.

A relative path such as lesson_data/notes.txt is interpreted relative to the program's current working directory when you actually open it. The browser console has its own temporary virtual filesystem; it cannot read a visitor's computer files just because a Path object names them. For portable display, as_posix uses forward slashes even if a local operating system stores paths differently. Creating a Path here does not create a directory or file.

PYTHON
from pathlib import Path
path = Path("lesson_data") / "notes.txt"
print(path.as_posix())
print(path.name)
print(path.stem)
print(path.suffix)
EXPECTED OUTPUT
lesson_data/notes.txt
notes.txt
notes
.txt
Follow the reasoning
  1. The / operator combines two path components without opening a file.
  2. name, stem, and suffix describe the final component.
  3. The path is relative; no file has been created yet.
02 / 03

Write and read inside a temporary directory

Path.write_text writes a string to a file, and Path.read_text reads it back. Specify an encoding so the program's intended text format is explicit. TemporaryDirectory creates a directory that is cleaned up when its with block ends. The example uses it to make a safe, repeatable exercise: it needs no pre-existing user file and does not leave lesson output behind in the browser's virtual filesystem.

The path exists inside the block, then disappears after cleanup. Notice that the Path object can still be held in a variable after the block, but it points to a location that no longer exists. The browser console's temporary filesystem is separate from files on your own computer. In a local Python script you could choose a real project directory, but you should decide where files belong and avoid overwriting a user's file accidentally.

PYTHON
from pathlib import Path
from tempfile import TemporaryDirectory

with TemporaryDirectory() as folder:
    path = Path(folder) / "notes.txt"
    path.write_text("first\nsecond\n", encoding="utf-8")
    print(path.read_text(encoding="utf-8").splitlines())
    print(path.exists())
print(path.exists())
EXPECTED OUTPUT
['first', 'second']
True
False
Follow the reasoning
  1. TemporaryDirectory creates an isolated folder for this run.
  2. write_text creates the file; read_text retrieves the UTF-8 content.
  3. Leaving the with block removes the temporary folder and its file.
03 / 03

Create missing parent folders deliberately

write_text can create a file, but it cannot create a missing parent directory. A nested path such as unit-1/lesson.txt will fail unless unit-1 exists. The parent attribute identifies that containing directory. Calling mkdir with parents=True builds any missing levels, and exist_ok=True lets the same preparation run when the directory already exists. The practice function save_note follows that sequence before writing UTF-8 text.

Creating directories is a persistent side effect in an ordinary local program, so choose the destination carefully. This example places the whole nested path under TemporaryDirectory and lets its cleanup remove it after the demonstration. In the browser console, the path exists only in the isolated virtual filesystem, not on a visitor's own computer. The function returns the filename and the text it read back so its behavior can be checked without assuming a particular temporary folder name.

PYTHON
from pathlib import Path
from tempfile import TemporaryDirectory

def save_note(path_text, note):
    path = Path(path_text)
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text(note, encoding="utf-8")
    contents = path.read_text(encoding="utf-8")
    return f"{path.name}: {contents}"

with TemporaryDirectory() as folder:
    path = Path(folder) / "unit-1" / "lesson.txt"
    print(save_note(str(path), "Review Path"))
    print(path.exists())
EXPECTED OUTPUT
lesson.txt: Review Path
True
Follow the reasoning
  1. mkdir creates the missing unit-1 parent directory.
  2. The file is written and read with an explicit UTF-8 encoding.
  3. The returned text depends on the filename and note, not on the temporary directory's name.

Try it in Python

Edit the example and run it. Python starts in your browser the first time you click Run.

Python console

Ready to run
Need input()? Add one value per line
Ctrl / ⌘ + Enter to run
OUTPUT
Your output appears here.
Your turnComplete save_note(path_text, note). Build a Path, create its missing parent folders, save note using UTF-8, read it back using UTF-8, and return '<filename>: <saved text>'. The filename is path.name, not the full path. The prepared call should print lesson-note.txt: Python paths are objects. A nested path must work, and a second call should overwrite the old note.
Need a hint?

Use path = Path(path_text); path.parent.mkdir(parents=True, exist_ok=True); path.write_text(note, encoding='utf-8'); saved = path.read_text(encoding='utf-8'); return f'{path.name}: {saved}'.

Complete the task and select Check task to verify your code.

    Quick quiz

    Three questions. You can change your answers and try again.

    01.What does (Path('reports') / 'year.txt').name return?

    02.Why call path.parent.mkdir(parents=True, exist_ok=True) before writing a nested file?

    03.What does Path.write_text do to an existing file?

    Typical mistakes

    Everyone meets these errors. See what causes them and how to fix them.

    Writing before the parent folder exists

    COMMON MISTAKE
    Path('notes/day-1.txt').write_text('hello', encoding='utf-8')
    FIX
    path = Path('notes/day-1.txt')
    path.parent.mkdir(parents=True, exist_ok=True)
    path.write_text('hello', encoding='utf-8')

    What happens: FileNotFoundError if notes has not been created.
    Create the containing folder first; parents=True also creates missing levels above it.

    Assuming write_text appends

    COMMON MISTAKE
    path.write_text('first', encoding='utf-8')
    path.write_text('second', encoding='utf-8')
    FIX
    path.write_text('first', encoding='utf-8')
    with path.open('a', encoding='utf-8') as file:
        file.write('second')

    What happens: The file contains only second.
    Use append mode explicitly when existing text must be kept.

    Joining path strings without a separator

    COMMON MISTAKE
    'reports' + 'summary.txt'
    FIX
    Path('reports') / 'summary.txt'

    What happens: The result is reportssummary.txt rather than a child file.
    The / operator on Path joins components using the current system's path rules.

    Browse this lesson’s problem fixes

    Sources and further reading