A missing source and an unreadable value are different problems. Treating both as zero would make a failed reading look like a genuine empty count. This exercise designs a small text reader with explicit outcomes, then checks it without opening an actual project file. The goal is a useful error report that preserves the distinction between absence, invalidity and a valid result.
Documentation boundary
Python documents FileNotFoundError for a requested file or directory that does not exist, and ValueError for an argument with an appropriate type but inappropriate value. The exercise handles those specific conditions separately; it does not turn every exception into a successful result.
Decide what each outcome means
A fictional text source is supposed to hold one nonnegative whole-number count. Leading and trailing whitespace are allowed. The agreed output has a status field and a count field. A missing source produces missing and no count. Non-numeric or negative content produces invalid and no count. A genuine zero produces ok with count zero. Write these rules before considering how the file is opened.
| Controlled source condition | Status | Count | Interpretation |
|---|---|---|---|
| Text: “7” with surrounding whitespace | ok | 7 | Valid reading |
| Text: many | invalid | None | Cannot interpret count |
| No requested file | missing | None | Source absent |
| Text: 0 | ok | 0 | Valid zero |
| Text: -2 | invalid | None | Outside agreed range |
Your tasks are to implement the three statuses, show that whitespace does not cause a valid count to fail, and demonstrate that an invalid reading cannot be confused with zero. Keep examples fictional. The worked checks replace the file-opening operation with controlled behaviour, so they do not depend on where a real document happens to be stored.
Worked reader and controlled checks
from unittest.mock import patch
def read_count(path):
try:
with open(path, encoding="utf-8") as stream:
raw = stream.read().strip()
except FileNotFoundError:
return {"status": "missing", "count": None}
try:
count = int(raw)
except ValueError:
return {"status": "invalid", "count": None}
if count < 0:
return {"status": "invalid", "count": None}
return {"status": "ok", "count": count}
from unittest.mock import mock_open
with patch("builtins.open", mock_open(read_data=" 7\n")):
assert read_count("fictional.txt") == {"status": "ok", "count": 7}
with patch("builtins.open", mock_open(read_data="many")):
assert read_count("fictional.txt")["status"] == "invalid"
with patch("builtins.open", side_effect=FileNotFoundError):
assert read_count("fictional.txt")["status"] == "missing"
print("three controlled cases passed")
The first check returns ok and seven. The second returns invalid. The third returns missing. A status is not merely decorative: a later report should only add a count when status is ok. For a missing or invalid record, show the relevant status instead of placing zero into a total. That preserves the meaning agreed in the table.
The file-opening step and value-conversion step have separate boundaries. This makes a failed opening distinguishable from content that was successfully read but could not be interpreted. The negative-value rule is part of this fictional task, not a universal rule for every numeric dataset. A different task might allow negative balances, so keep range policy visible rather than burying it in a reusable generic reader.
Diagnose overbroad recovery
Suppose a modified reader returns ok and zero inside a broad exception handler. It appears robust because the programme continues, but it has discarded the reason for failure. Repair the contract before repairing presentation: restore the separate status and no-count outcomes. Then add a check that a genuine zero remains distinguishable from invalid content. Continuing execution is only useful when the result still means what the caller expects.
Do not catch permission errors merely to make this exercise pass. The present reader handles the stated missing-file case and invalid count; an unexpected opening failure should remain visible for diagnosis. If your real application needs an additional permission-denied outcome, define and test that policy separately. Inventing an empty count during an access problem would conceal an operational issue rather than resolve it.
Complete the error report
Extend the controlled checks with empty text, a negative count and a genuine zero. Under this contract the expected statuses are invalid, invalid and ok. Record the actual count only for the zero case. Then write a short caller rule: display valid counts, request correction for invalid content, and request a source for missing content. These are exercise decisions, not instructions to contact a real person or service.
A complete submission includes the outcome table, the reader, the controlled checks and a short explanation of one deliberately unhandled failure. Explain why no-count is different from count zero. For further practice, design a separate decimal-reading contract rather than weakening this one until every string is accepted. Different accepted formats deserve explicit rules and examples.
Questions for this exercise
Which exception distinguishes a missing source?
The documented FileNotFoundError identifies the missing-file condition handled by this exercise.
Do the checks need an actual file?
No. They replace file opening with controlled fictional text or a controlled missing-file exception.
Why is a valid zero important?
It proves that absence and invalid content have not been silently converted into an empty count.
Official documentation
Explore the Courses overview or use Contact for general enquiries. This is an original INTIAU editorial self-study exercise; no qualification is awarded.
Related guides
View the study diagram

