Unit 09 · lesson

Paths, Missing Files, and File Organization

Core path: 30 minutes

When Python says a file does not exist, what exactly does that claim mean?

It does not necessarily mean the file is nowhere on your computer.

It means the path Python tried to resolve did not lead to the requested file from the execution context it was using.

That wording is more precise, and it gives you something to investigate.

A filename without a directory is still a path

Suppose:

player-manager/
├── main.py
└── data/
    └── players.txt

From the project root, this:

open("players.txt")

asks for a file named players.txt relative to the current working directory.

But the actual file is at:

data/players.txt

So:

with open("data/players.txt", "r") as file:
    ...

matches the project structure when the working directory is the project root.

Relative paths depend on the working directory

This is the same shell concept from Week 2 coming back inside your Python application.

If the working directory is:

/player-manager

then:

data/players.txt

resolves to:

/player-manager/data/players.txt

But if the program is launched while the working directory is:

/player-manager/data

then the same relative path may be interpreted as:

/player-manager/data/data/players.txt

which probably does not exist.

The source code did not change.

The execution context did.

FileNotFoundError is filesystem evidence

When Python raises:

FileNotFoundError

start with these questions:

What exact path did the program request?
What is the process working directory?
Does that resolved path exist?
Is capitalization/spelling exact?

Use shell evidence:

pwd
ls

or inspect the path from Python:

from pathlib import Path

print(Path.cwd())

Do not rewrite file-handling logic before checking the location the program is actually using.

The editor's Explorer is only one view

A file can be clearly visible in VS Code while a relative open() call still fails.

Why?

The Explorer may show the entire project tree.

The process resolves a relative path from its current working directory.

Those are related but not identical contexts.

Again: interface layer versus runtime state.

pathlib makes path operations more explicit

from pathlib import Path

DATA_FILE = Path("data") / "players.txt"

Then:

print(DATA_FILE)
print(DATA_FILE.exists())

You can also inspect an absolute resolved representation:

print(DATA_FILE.resolve())

That output can be extremely useful during debugging because it shows which concrete location the relative path maps to from the current environment.

Existence checks are not universal error handling

if DATA_FILE.exists():
    print("File found")
else:
    print("File missing")

That can be appropriate when a missing file is an expected state.

For example, a new roster application might legitimately start with no save file and treat that as an empty roster.

But if the application requires a configuration file, silently pretending a missing file is fine could hide a serious setup error.

Error handling should match the contract.

Organize persistent data intentionally

This communicates separation:

my-project/
├── main.py
├── data/
│   ├── players.json
│   └── scores.csv
├── tests/
└── README.md

The data/ folder tells another developer that those files are application data, not Python modules.

Do not create directories only to imitate large repositories. Use them when they make a real project relationship clearer.

Avoid hard-coded personal absolute paths

This may work only on one machine:

open("C:/Users/Nova/Desktop/project/data/players.txt")

or:

open("/home/nova/project/data/players.txt")

Now the source code contains assumptions about one user's filesystem.

Portable project code usually works from project-relative locations or derives paths from a known project/module location.

We will keep the beginner examples simple, but recognize the smell: your username and Desktop path should not be part of the application architecture.

A more stable path relative to the source file

There is an important distinction between:

current working directory

and:

directory containing this Python file

For projects where launch location may vary, code can derive a path from the module file:

from pathlib import Path

BASE_DIR = Path(__file__).resolve().parent
DATA_FILE = BASE_DIR / "data" / "players.txt"

Now DATA_FILE is based on where main.py lives rather than whichever directory the shell happened to be in when the process launched.

You do not need to use this pattern in every tiny script this week. I want you to understand why it exists.

Guided failure investigation

Given:

from pathlib import Path

path = Path("data/players.json")

with open(path, "r") as file:
    print(file.read())

and a FileNotFoundError, collect:

print("cwd:", Path.cwd())
print("requested:", path)
print("resolved:", path.resolve())
print("exists:", path.exists())

Then inspect the actual filesystem.

The evidence should let you describe the failure more precisely than:

Python can't find my file.

A useful explanation is:

The program is running with /workspace/project/tests as its working directory, so data/players.json resolves under tests/data/, but the file is actually at /workspace/project/data/players.json.

Now you know what needs to change.

Before structured formats

Lesson 3 changes the question from:

Where is the file?

to:

What representation should the file use, and how does Python reconstruct data from it?

The path gets you to the file. The format tells you how to interpret its contents.

Vocabulary lab

Flip the idea, not just the card

Explain the term before you reveal the back. Then compare your explanation with the definition, example, and warning.

1 / 5
Read all terms without animation
File Path
A description of a file or directory location in a filesystem. Example: data/players.txt. Do not confuse it with: The contents stored inside that file.
Relative Path
A path interpreted from a current base location such as the process working directory. Example: data/config.json from the project root. Do not confuse it with: An absolute path that identifies a location from a filesystem root or drive.
Working Directory
The directory used as the base for many relative filesystem operations in the running process. Example: Path.cwd() reports the current working directory. Do not confuse it with: The directory containing the Python source file unless those happen to be the same location.
FileNotFoundError
An exception raised when a requested filesystem path cannot be opened because the target is not found at that resolved location. Example: Opening data/players.json from a working directory where that relative path does not exist. Do not confuse it with: A JSON parsing error after the file was successfully opened.
Absolute Path
A path that identifies a location starting from a filesystem root or drive rather than from the current directory. Example: /home/student/project/data.json or C:\Users\Student\project\data.json. Do not confuse it with: A portable project-relative path.