One useful idea
A Path represents a location. The / operator joins path components using the host operating system’s separators. Creating a Path does not create a directory.
resolve() produces an absolute path and follows existing symbolic links. A candidate that looks nested can still resolve outside the chosen root. Use candidate.is_relative_to(base) after resolving both to reject that escape. This is a preview check, not permission to write; future write operations need their own safety checks.
The delivery date is an input, not an implicit “today”. date.fromisoformat checks a real calendar date; compare isoformat() back to the input to require canonical YYYY-MM-DD. This makes previews repeatable.
Refresh first: Single-component validation, Reading practice files.
Trace a finished example
from pathlib import Path
from asset_tools import output_path
root = Path.cwd() / "sample-output"
planned = output_path(root, "Museum", "2026-10-08")
print(planned)
# Absolute path ending in Museum/deliveries/2026-10-08
# No directory is created.The root is resolved, Museum is validated as one component, the date is checked, and the destination is composed and resolved. Only a contained candidate is returned; no mkdir, rename or write follows.
The finished implementation is in asset_tools.py. Reading it is guided practice, not independent evidence.
Predict before running
Does Path("sample-output") / "Museum" create either folder?
Compare your answer · self-reviewed
No. It constructs a path value. A method such as mkdir would perform I/O; this preview deliberately does not call one.
Find the bug
What is wrong with accepting ../outside as the project component?
Compare your answer · self-reviewed
It describes movement up a directory, not a single project name. Validate the component before joining and check the resolved destination remains under the root.
Explain the result
Why can the same result display with backslashes on Windows and slashes on macOS?
Compare your answer · self-reviewed
Path uses the local operating system’s conventions. Test the path components and containment, not one hardcoded separator string.
Change it, then build your own
One controlled change
Preview the same root and project on two dates. Only the final date component should change. Try 2026-02-30 and predict the validation error.
Your independent task
Implement output_path in practice.py. Accept a non-empty str or Path root, validate project with safe_component, validate the canonical delivery date with datetime.date, and resolve base and candidate. Refuse candidates outside base with ValueError. Return a Path; do not create, delete, move or rename anything.
What success looks like
Three path test methods pass: composition, invalid root/project/date inputs and a simulated resolved path escape. Paths displayed in your terminal may use different separators from the illustration.
Hint 1 · a question
Write the four components: root, project, deliveries, date. Which are trusted constants and which need validation?
Hint 2 · a concept cue
Keep the resolved base separate from the resolved candidate. A prefix such as /media-bin and /media-bin-other is not containment.
Hint 3 · a localized example
Use base / project / "deliveries" / delivery_date, then resolve and is_relative_to(base). Return the path only after validation.
Need the complete worked solution?
Open asset_tools.py from the kit. Trace it, close it, then try fresh inputs in your own files. Treat the attempt as guided; seeing the solution does not award a practical pass.
Course help is guidance, not independent evidence. With JavaScript, opening help records guidance locally; otherwise note it in your README. Reset does not erase that history.
Repair a failed check
If the result is relative, resolve it before returning. If a bad date passes, parse a calendar date rather than checking only its string shape. If the escape check fails, compare resolved Paths rather than raw string prefixes.
NotImplementedError means a practice stub is still unfinished. Read the failing test name and the last error line. Change one behavior, rerun that build, then rerun all implemented builds.
Show it works on new inputs
Use project Museum and date 2026-10-08 with a temporary sample root. Confirm the returned components and that no directory appeared. Explain why a preview is safer than an automatic rename.
Self-review: name the input, result, refused case and reason. Your local test output and explanation are separate from a quiz score; this page does not certify a pass.
Keep the idea
Path composition is not filesystem mutation. Validate data and containment now; postpone writes until a later, explicitly designed operation.