Decide what is worth automating, describe its inputs and outputs, and build scripts that plan before they act.
About 35 minBeginner3 exercisesFree
You will be able to
Judge whether a repetitive task is a good candidate for automation
Describe an automation as inputs, steps and outputs before writing code
Separate planning from acting so a script can run in dry-run mode
Refuse to overwrite or destroy files without an explicit check
Every Monday, Hana in the accounts team of a small trading company downloads about forty scanned invoices. The scanner names them Invoice March 03.PDF, invoice march 04.pdf, INVOICE-March-05.pdf. She renames each one by hand to a consistent lower-case form so the archive sorts properly. It takes twenty minutes, she does it 50 times a year, and every few weeks she makes a typo that hides an invoice.
That is a perfect job for Python. But a script that renames forty files in a second can also ruin forty files in a second. This track is about automation you can trust: scripts that show you what they are about to do, never destroy data by accident, and can be run again safely.
What is worth automating?
A task is a good candidate when most of these are true:
Question
Good sign
How often does it happen?
Daily, weekly or monthly
Are the rules clear?
You could write them as a checklist
Is it error-prone by hand?
Copying, retyping, renaming, comparing
Are the inputs predictable?
Same folder, same export format
What if it goes wrong?
Mistakes are visible and recoverable
A task that needs judgement each time ("decide which customers deserve a discount") is a poor candidate. A task with clear rules ("rename every scan to lower case with underscores") is a good one.
Before writing code, describe the automation in three parts:
Inputs: what it reads (a folder of scans, a CSV export, a config file).
Steps: the rules, in order (clean each name, skip names already clean, rename).
Outputs: what changes or gets produced (renamed files, a report, a log of what happened).
Writing these down usually reveals the awkward questions early: what if two scans clean to the same name? What if the folder is empty?
Safe automation principles
These habits appear in every lesson of this track:
Plan, then act. First build a list of the changes the script would make. Show it. Only apply it when asked. Running with only the plan is called a dry run.
Never destroy originals. Prefer copying to moving, and moving to deleting. Never delete without an explicit confirmation.
Check before you overwrite. If the target file already exists, stop or pick a new name.
Record what happened. Print or log every change so you can explain (and undo) it later.
Make re-runs safe. Running the script twice should not do the work twice or damage anything. This property is called idempotence.
Fail loudly. If something unexpected turns up, stop with a clear message rather than guessing.
Plan first: build the list of renames without touching any file
defclean_name(name):
return name.strip().lower().replace(" ","_")
scans =["Invoice March 03.PDF","invoice_march_04.pdf","Receipt Fuel.png"]
plan =[]for name in scans:
new = clean_name(name)if new != name:
plan.append((name, new))for old, new in plan:
print(f"WOULD RENAME {old} -> {new}")print(len(plan),"of",len(scans),"files need renaming")
Try it: Add the name " Credit Note 7.pdf" (with leading spaces) to the list and run it. Which part of clean_name handles the spaces?
Nothing on disk changed: the program only built a plan, a list of (old, new) pairs. Notice that invoice_march_04.pdf is already clean, so it is left out of the plan. That matters later: when you run the script a second time, the plan is empty and nothing happens. That is idempotence in its simplest form.
Keeping the plan as data has another benefit: you can test the planning logic with plain lists, without creating any files.
A dry-run switch
The usual shape is one function that applies a plan, with a dry_run parameter that defaults to True. Forgetting the argument should give you the safe behaviour, not the destructive one.
Predict the output
defapply(plan, dry_run=True):
done =[]for old, new in plan:
if dry_run:
print("WOULD RENAME", old,"->", new)else:
done.append(new)print("RENAMED", old,"->", new)return done
plan =[("A.txt","a.txt")]print(apply(plan))print(apply(plan, dry_run=False))
Confirm before anything destructive
Some jobs really do need to delete files, such as clearing out temporary exports. Make the script ask first, and treat anything other than an exact "yes" as no:
Ask for confirmation; the default answer is no
old_exports =["export_0101.tmp","export_0102.tmp","export_0103.tmp"]print("These files would be deleted:")for name in old_exports:
print(" ", name)
answer =input("Type yes to delete them: ")if answer.strip().lower()=="yes":
print("Deleting",len(old_exports),"files")else:
print("Nothing deleted.")
Input given to the program: "no"
Try it: Change the input to Yes (with a capital Y) and run it again. Then try y. Which answers count as confirmation?
Guided practice · ●●difficulty 2 of 5 · about 6 min
Plan the renames
Write plan_renames(names) that takes a list of file names and returns the plan: a list of (old, new) tuples for the names that need renaming.
The clean form of a name is: surrounding spaces removed, all lower case, and every remaining space replaced by an underscore. Names that are already clean must not appear in the plan. Keep the original order.
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Challenge · ●●●difficulty 3 of 5 · about 10 min
Apply a plan with a dry-run switch
The working folder contains a scans/ folder with Invoice March.pdf and Receipt 01.png.
Write apply_plan(plan, folder, dry_run=True). For each (old, new) pair in plan:
in a dry run, rename nothing and add the message "WOULD RENAME old -> new";
otherwise rename folder/old to folder/new and add "RENAMED old -> new".
Return the list of messages. dry_run must default to True, so a call without it never changes anything.
Use pathlib.Path ((Path(folder) / old).rename(...)). Do not call the function at the top level of your program.
Files in your working folder: scans/Invoice March.pdfscans/Receipt 01.png
scans/Invoice March.pdf
scanned invoice for March
scans/Receipt 01.png
scanned receipt 01
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Edge cases · ●●●difficulty 3 of 5 · about 8 min
Never overwrite on rename
On Linux and macOS, renaming a file onto an existing name silently replaces the existing file. (On Windows, Path.rename raises FileExistsError instead, so the same script behaves differently on different computers. Checking first gives one predictable behaviour everywhere.) Write rename_safely(folder, old, new) that renames folder/old to folder/new only when it is safe, and returns a status string:
Situation
Return
Files
old and new are the same name
"same"
unchanged
folder/old does not exist
"missing"
unchanged
folder/new already exists
"exists"
unchanged
otherwise
"renamed"
renamed
Check the situations in that order.
rename_safely("docs","draft.txt","final.txt")# "renamed"
rename_safely("docs","draft.txt","final.txt")# "missing" (it was already renamed)
Files in your working folder: docs/draft.txt
docs/draft.txt
Quarterly plan, draft 3
Python code editor. Tab indents. Press Escape then Tab to leave the editor. Control or Command plus Enter runs the code; Shift plus Enter checks your answer.
Ctrl+Enter run · Shift+Enter check · your code is saved in this browser as you type
Output
Run your code to see its output, or Check to test it against the requirements.
The solution becomes available after you pass, or after all three hints and two checks.
Summary
Automate tasks that are frequent, rule-based and error-prone by hand; describe them as inputs, steps and outputs first.
Build a plan (a list of changes) before acting, and offer a dry run that reports the plan without changing anything.
Make dry_run=True the default so the destructive path has to be requested.
Check before overwriting, ask before deleting, and return or record a status for every action.
Skip work that is already done so the script can be re-run safely.