Quiz — Chapter 17: Automating Repetitive Office Tasks
Questions
1. You want to find all .xlsx files in a directory and all its subdirectories using pathlib. Which method do you use?
A) path.glob("*.xlsx")
B) path.rglob("*.xlsx")
C) path.iterdir("*.xlsx")
D) path.find("**/*.xlsx")
2. Which statement correctly builds a cross-platform file path using pathlib?
A) Path("/data") + "reports" + "2024-01" + "sales.csv"
B) Path("/data/reports/2024-01/sales.csv")
C) Path("/data") / "reports" / "2024-01" / "sales.csv"
D) Both B and C are correct
3. What does Path.mkdir(parents=True, exist_ok=True) do?
A) Creates only the final directory and raises an error if it already exists B) Creates the directory and all missing parent directories; does nothing if it already exists C) Creates the directory only if the parent already exists; raises an error if it already exists D) Creates the directory and deletes any existing contents
4. You run shutil.move("/data/exports/report.csv", "/data/archive/report.csv"). A file called report.csv already exists in /data/archive/. What happens?
A) The move is cancelled and an error is raised B) The destination file is overwritten C) The source file is renamed with a numeric suffix automatically D) The source file is copied but not deleted
5. In the automation audit matrix, a task scores: Time = 2 minutes, Frequency = 3 times per year, Consistency = Very consistent. What is the best course of action?
A) Automate immediately — consistency alone justifies it B) Do not automate — the time savings don't justify the development investment C) Automate only if it is part of a larger workflow D) Convert to a cron job regardless
6. What is the primary advantage of watchdog over a polling loop (a while True: loop that checks for new files every few seconds)?
A) watchdog is written in pure Python; polling requires C extensions B) watchdog uses OS-level notifications and only activates on actual changes; polling consumes CPU continuously C) watchdog works on all file systems; polling only works on local drives D) watchdog can process multiple files simultaneously; polling processes one at a time
7. Which of the following is the correct way to get a file's last modification date from a Path object?
A) file_path.modified_date
B) datetime.fromtimestamp(file_path.stat().st_mtime)
C) file_path.get_modification_time()
D) os.path.getmtime_date(file_path)
8. The chapter recommends always implementing dry-run mode in file automation scripts. Which of the following best describes the purpose of dry-run mode?
A) To run the script faster by skipping error handling B) To test the script on a copy of the real data rather than the original C) To show what the script would do without actually moving, renaming, or deleting any files D) To disable logging for cleaner output during development
9. You want to archive an entire folder tree (including all subfolders and files) into a single ZIP file. Which function should you use?
A) shutil.copy2(source_dir, output.zip)
B) shutil.make_archive(base_name, "zip", root_dir, base_dir)
C) zipfile.ZipFile(source_dir).compress()
D) os.archive(source_dir, "zip")
10. What does Path.suffix return for the file quarterly_report_v2.XLSX?
A) "xlsx"
B) ".XLSX"
C) ".xlsx"
D) "XLSX"
11. In Windows Task Scheduler, you want to run a Python script if it exits with a non-zero code. This requires that your script:
A) Prints "ERROR" to stdout when something goes wrong
B) Raises an unhandled exception to crash the process
C) Calls sys.exit(1) (or any non-zero integer) on failure
D) Writes to a specific log file that Task Scheduler monitors
12. The resolve_naming_conflict() function in the chapter renames chicago.csv to chicago_1.csv if chicago.csv already exists. If chicago_1.csv also exists, what does it produce?
A) chicago_1_1.csv
B) chicago(2).csv
C) chicago_2.csv
D) chicago_copy.csv
13. You want to organize files by their modification date into monthly folders (like 2024-01, 2024-02). Which datetime method formats a datetime object as "2024-01"?
A) dt.strftime("%Y/%m")
B) dt.strftime("%Y-%m")
C) dt.isoformat()[:7]
D) Both B and C produce the same result
14. Priya's morning script exits with sys.exit(1) when regional files are missing. Why is this preferable to just logging a warning and exiting with sys.exit(0)?
A) sys.exit(1) is faster than sys.exit(0)
B) Task Scheduler and other automation systems treat non-zero exit codes as failures and can trigger alerts; exit code 0 would mark a failed run as successful
C) sys.exit(0) suppresses all output; only sys.exit(1) allows log files to be written
D) There is no practical difference — both are acceptable approaches
15. Which of the following pathlib features makes it preferable to os.path for most file operations?
A) pathlib functions are always faster than os.path equivalents
B) pathlib works on Python 2; os.path requires Python 3
C) Path objects combine path manipulation and file operations in a single, readable API; the / operator builds paths readably without string concatenation
D) pathlib automatically handles network paths; os.path does not
16. In watchdog, what is the difference between the on_created and on_moved event handlers?
A) on_created fires for all new files; on_moved only fires for renamed files within the same directory
B) on_created fires when a new file is written in the watched folder; on_moved fires when a file from outside is moved into the watched folder (or when a file is renamed)
C) on_created fires for files; on_moved fires for directories
D) They are identical — watchdog uses them interchangeably
17. What does shutil.copytree() do?
A) Copies a single file and all its metadata B) Copies a directory and all its contents recursively to a new location C) Creates a symlink pointing to the source directory D) Moves a directory tree to a new location
18. You want to find all files in a folder that are larger than 50 MB. Which approach is correct?
# Approach A
for f in folder.iterdir():
if f.is_file() and f.size > 50_000_000:
print(f.name)
# Approach B
for f in folder.iterdir():
if f.is_file() and f.stat().st_size > 50_000_000:
print(f.name)
A) Approach A — Path objects have a .size attribute
B) Approach B — file size is accessed through Path.stat().st_size
C) Neither — you need to use os.path.getsize()
D) Both approaches are equivalent
Answer Key
| Q | Answer | Explanation |
|---|---|---|
| 1 | B | rglob() searches recursively (all subdirectories); glob() only searches one level. |
| 2 | D | Both are valid. The / operator form (C) is preferred for readability in complex paths. |
| 3 | B | parents=True creates missing ancestors; exist_ok=True suppresses the error if the directory already exists. |
| 4 | B | shutil.move() overwrites the destination if it exists. Your script must handle conflicts before calling it. |
| 5 | B | 3 times per year × 2 minutes = 6 minutes/year saved. Unless the script takes minutes to write, the ROI is questionable. |
| 6 | B | watchdog uses OS-level mechanisms (inotify, FSEvents, ReadDirectoryChanges). Polling wastes CPU checking repeatedly even when nothing changes. |
| 7 | B | stat().st_mtime returns a float timestamp; wrap it with datetime.fromtimestamp() for a usable datetime object. |
| 8 | C | Dry-run mode previews actions without side effects. It is the professional way to verify file operations before committing. |
| 9 | B | shutil.make_archive() creates ZIP or TAR archives from directory trees. |
| 10 | B | Path.suffix returns the extension as-is, preserving case. Use .suffix.lower() if you need case-insensitive matching. |
| 11 | C | sys.exit(1) sets the process exit code. Task Scheduler checks this to determine success or failure. |
| 12 | C | The loop increments the counter until it finds a name that doesn't exist: chicago_1.csv exists → try chicago_2.csv. |
| 13 | D | strftime("%Y-%m") and isoformat()[:7] both produce "2024-01". The strftime form is more explicit. |
| 14 | B | Exit codes are the interface between a script and its orchestrator. Non-zero exit codes trigger failure handling (alerts, retries) in Task Scheduler, cron, CI systems, etc. |
| 15 | C | The / operator and the combined API make pathlib significantly more readable than string-based os.path calls, especially in complex scripts. |
| 16 | B | on_created fires when a file is newly written in the watched folder. on_moved fires when a file is renamed or moved in from another location. Implementing both ensures no files are missed. |
| 17 | B | shutil.copytree() recursively copies an entire directory tree to a new destination path. |
| 18 | B | Path objects do not have a .size attribute. File size is accessed via f.stat().st_size, which returns bytes. |