programming · Level 2

Python: from first script to a useful automation

Install Python, learn the basics, then build, test and safely use a small tool that tidies and reports on a folder.

By Mickarle Wagstaff-Irons - Micky Irons

  • Level 2Getting going
  • 140 min
  • 6 chapters
  • Online course and PDF workbook
The Sequenceprogramming / 02

Read, practise and review

Your next step

Start this course online

Register your start, then work through the lessons and exercises at your own pace. You can download the PDF separately. Where a scored exam is available, you will find it after the lessons.

Register or resume your course

Mickai privately records this registration and sends its team a course-start notification. It records your intention to start, not proof of attendance or completion. Our course-start privacy notice explains the details and the 30-day resume cookie.

Follow the Mickai company page on LinkedIn

You can start learning without subscribing or following. Newsletter email confirmation and provider enrolment are recorded separately.

Start with the essentials

The short answer

Python is a free, general-purpose programming language that suits routine computer tasks. Install it from python.org, save a script as a plain text file and run it from a terminal. A safe first automation reads before it writes, defaults to a dry run, never deletes anything and has a simple test behind it before you point it at real files.

What you will learn

  • You will be able to install Python, run a script and read its output and its error messages.
  • You will be able to write short programs using variables, decisions, loops and functions.
  • You will be able to read and write text and CSV files and handle errors without hiding them.
  • You will have built, tested and safely run a small tool that sorts and reports on a folder.
  • You will be able to review a script written by someone else, or by an AI assistant, before you run it.

Who it is for

Complete beginners to programming who want to automate something real. You should be comfortable saving files and willing to type commands into a terminal window. No earlier coding experience is needed.

Before you start

  • None. You need a computer you can install free software on, and a willingness to type and run small programs. The Your first prompts workbook is helpful if you want to use an AI assistant alongside the exercises.

Learn in your browser · Chapter 01 of 06

01

Install Python and run a script

Install Python, try one line, then run a saved script.

A script is a plain text file of instructions. Python, the interpreter, carries them out from top to bottom. Automation means writing them once and running them whenever you like.

Installing. Get Python from python.org and follow its current instructions, because they change. On Windows, the Python documentation recommends the Python install manager and calls the older full installer deprecated. Recent macOS versions include a python3 command meant for Apple's own tools, so you can install a current version from python.org alongside it. Most Linux systems already have Python or offer it as a package.

Choose a supported version: python.org lists them, and at the time of writing supports each for five years. This workbook was tested on Python 3.12.10 on Windows 11 and uses only what comes with Python.

Open a terminal (Terminal on macOS and Linux, PowerShell on Windows) and type the first line. The second is the reply, and yours may differ.

text · 2 lines
python --version
Python 3.12.10

On macOS and Linux the command is python3, so type that wherever this workbook says python. On Windows, py also works. The command alone opens the interactive prompt (>>>), where each line runs at once. Leave with quit().

To keep your work, write a script. Save this as hello.py in a folder called python-first, using a plain text editor (check the name ends .py, not .py.txt). Open a terminal there, or use cd python-first, and run it. The # line is a comment that Python ignores.

python · 3 lines
# hello.py: my first script
print("Hello from Python")
print(6 * 7)

text · 3 lines
python hello.py
Hello from Python
42

Try it yourself · Activity 01

15 min

Install and run

Get Python working, then change your first script.

  1. Install Python and run the version command.
  2. Save hello.py in python-first and run it.
  3. Add a line that prints 60 * 24 and run it again.

What went wrong first, and how did you fix it?

Worked answer

Your version number may differ. The first run prints Hello from Python, then 42. The new line prints 1440, the minutes in a day. If Python is not found, try py or python3, or repeat the install and read any prompt about your PATH (where your computer looks for programs).

Next chapter

Learn in your browser · Chapter 02 of 06

02

Values, decisions and loops

Programs remember values, make decisions and repeat work. Learn these three and you can read most short scripts.

A variable is a name attached to a value, as in price = 2.5. Every value has a type that decides what you can do with it.

Scroll sideways to see every column.

Values, decisions and loops · Table 1
TypeHoldsExample
strText"tea"
intWhole numbers3
floatDecimal numbers2.5
boolTrue or FalseTrue
listAn ordered collection["tea", "cake"]
dictLabels with values{"tea": 2.5}

3 is a number but "3" is text, and Python will not add the two: it stops with a TypeError rather than guess.

Decisions use if, elif and else; loops use for. Indentation shows what belongs inside, so keep it consistent. An f-string such as f"Total: {total:.2f}" puts a value in text, and .2f means two decimal places.

python · 11 lines
prices = {"tea": 2.5, "coffee": 3.0, "cake": 4.25}
order = ["tea", "cake", "cake", "juice"]

total = 0.0
for item in order:
    if item in prices:
        total = total + prices[item]
    else:
        print(f"No price for {item}, skipping it")

print(f"Total: {total:.2f}")

text · 2 lines
No price for juice, skipping it
Total: 11.00

Read it aloud: for each item, if we have a price add it, otherwise say so.

Try it yourself · Activity 02

15 min

Change the order

Predict before you run, then check yourself.

  1. Save it as order.py, predict the output, then run it.
  2. Add "coffee" to the order and predict again.
  3. After the loop, take 10 per cent off if the total is above 10.

Which prediction was wrong, and why?

Worked answer

The first run prints No price for juice, skipping it, then Total: 11.00. With coffee it is 14.00. After the loop, if total > 10: with total = total * 0.9 indented beneath it gives Total: 12.60.

Next chapter

Learn in your browser · Chapter 03 of 06

03

Functions, files and paths

Functions organise your work, and files and paths are how scripts touch the real world.

A function starts with def, takes inputs (parameters) and hands back a result with return. The triple-quoted docstring says what it is for. Small, well-named functions are easy to read, reuse and test.

python · 12 lines
from pathlib import Path

GROUPS = {".jpg": "Images", ".png": "Images", ".pdf": "Documents", ".txt": "Documents", ".csv": "Data"}


def group_for(filename):
    """Return the group for a file name, judged by its extension."""
    return GROUPS.get(Path(filename).suffix.lower(), "Other")


print(group_for("Holiday.JPG"))
print(group_for("readme"))

text · 2 lines
Images
Other

.lower() makes Holiday.JPG match .jpg. .get(key, default) falls back to Other for unknown types.

Paths. pathlib.Path treats a path as an object: Path("practice") / "notes.txt" joins pieces with your system's separator. Useful tools:

  • path.name and path.suffix give the file name and extension.
  • path.exists() and path.is_file() ask questions and change nothing.
  • folder.iterdir() lists a folder in arbitrary order, says the documentation, so use sorted(...).
  • path.read_text(encoding="utf-8") reads a file. path.write_text(...) writes one, replacing any existing file.

The dry-run habit. A script that changes files should do nothing until you ask. sys.argv lists the words on the command line, starting with the script name, so "--create" in sys.argv is true only if you typed the flag. Save this as make_practice.py.

python · 13 lines
import sys
from pathlib import Path

NAMES = ["holiday.jpg", "budget.CSV", "notes.txt", "scan.pdf", "readme", "logo.png"]
create = "--create" in sys.argv
folder = Path("practice")

if create:
    folder.mkdir()
for name in NAMES:
    print("Creating" if create else "Would create", name)
    if create:
        (folder / name).write_text("practice file\n", encoding="utf-8")

Run it plain, read the plan, then add --create. If practice exists, mkdir stops with an error rather than mixing files in.

Try it yourself · Activity 03

20 min

Count the practice files

Count the practice files by group with a function.

  1. Make the practice folder.
  2. In count.py, copy the code above without the print lines.
  3. Add count_by_group(folder): loop over Path(folder).iterdir(), skip non-files and count per group.
  4. Print the counts alphabetically.

What does is_file() protect you from, and why sort?

Worked answer

Four lines: Data 1, Documents 2, Images 2, Other 1. Start with counts = {}. In the loop: group = group_for(item.name) then counts[group] = counts.get(group, 0) + 1. Return counts, then print with for group, n in sorted(counts.items()): print(group, n).

Next chapter

Learn in your browser · Chapter 04 of 06

04

Text, CSV and things going wrong

Real data is messy, so learn to read files and to fail well.

Open files inside a with block, which closes the file even if something goes wrong. Always pass encoding="utf-8", because up to Python 3.14 the default depends on your platform. The mode sets the risk.

Scroll sideways to see every column.

Text, CSV and things going wrong · Table 2
ModeMeaningRisk
"r"Read only (the default)None
"x"Create new, fail if it existsLow
"a"Add to the endMedium
"w"Write, emptying the file firstHigh

CSV (comma-separated values) is the plain text format that spreadsheets export. csv.DictReader gives each row as a dictionary keyed by the header names. The documentation says to open CSV files with newline="". Save this as spending.csv, as plain text.

text · 5 lines
date,category,amount
2026-09-01,Food,12.50
2026-09-01,Travel,40.00
2026-09-02,Food,7.25
2026-09-03,Travel,abc

The last row is deliberately bad. This script totals each category and counts the rows it skips.

python · 22 lines
import csv


def total_by_category(path):
    totals = {}
    skipped = 0
    with open(path, newline="", encoding="utf-8") as f:
        for row in csv.DictReader(f):
            try:
                amount = float(row["amount"])
            except ValueError:
                skipped += 1
                continue
            category = row["category"]
            totals[category] = totals.get(category, 0) + amount
    return totals, skipped


totals, skipped = total_by_category("spending.csv")
for category, amount in sorted(totals.items()):
    print(f"{category}: {amount:.2f}")
print(f"Skipped {skipped} unreadable row(s)")

text · 3 lines
Food: 19.75
Travel: 40.00
Skipped 1 unreadable row(s)

Without the try, that row would stop the script with a traceback. Read it from the bottom: the last line names the problem, here ValueError: could not convert string to float: 'abc'. Catch the specific error you expect, never a bare except:.

Try it yourself · Activity 04

20 min

Break it on purpose

Feed the script two new kinds of bad row.

  1. Run spending.py on spending.csv.
  2. In a plain text editor, add 2026-09-04,Food, and 2026-09-05,Travel as new lines. Save as UTF-8.
  3. Predict the result, then run again.
  4. Read the last line of the error and fix the except line.

How does an empty value differ from a missing one?

Worked answer

The empty amount raises ValueError and that row is skipped. The short row makes row["amount"] be None, so the script stops with a TypeError. With except (ValueError, TypeError): the output is Food: 19.75, Travel: 40.00, Skipped 3 unreadable row(s).

Next chapter

Learn in your browser · Chapter 05 of 06

05

Build the folder tool, dry run first

Combine everything into one tool that sorts a folder's files by type and reports what it did.

Write the rules before the code.

  • Plan first. One function works out every move and changes nothing.
  • Dry run by default. Nothing moves without --apply.
  • Never delete or overwrite. If a name is taken, skip the file and say so.
  • Keep a log. Each move goes into a CSV file, so you can undo it by hand.

Save this as tidy.py, outside the folder you will tidy.

python · 72 lines
"""tidy.py: sort the files in ONE folder into sub-folders by type. A dry run by default."""
import argparse
import csv
from datetime import datetime
from pathlib import Path

GROUPS = {".jpg": "Images", ".png": "Images", ".pdf": "Documents", ".txt": "Documents", ".csv": "Data"}


def group_for(filename):
    return GROUPS.get(Path(filename).suffix.lower(), "Other")


def plan_moves(folder):
    """List (source, destination) pairs. Changes nothing."""
    moves = []
    for item in sorted(folder.iterdir()):  # no fixed order, so sort
        if item.is_file() and not item.name.startswith((".", "tidy-log")):
            moves.append((item, folder / group_for(item.name) / item.name))
    return moves


def apply_moves(moves):
    rows = []
    for source, destination in moves:
        if destination.exists():
            result = "skipped: name already exists"
        else:
            try:
                destination.parent.mkdir(exist_ok=True)
                source.rename(destination)
                result = "moved"
            except OSError as error:
                result = f"failed: {error}"
        rows.append({"file": source.name, "to": destination.parent.name, "result": result})
    return rows


def write_log(folder, rows):
    name = f"tidy-log-{datetime.now():%Y%m%d-%H%M%S-%f}.csv"
    with open(folder / name, "x", newline="", encoding="utf-8") as f:
        writer = csv.DictWriter(f, fieldnames=["file", "to", "result"])
        writer.writeheader()
        writer.writerows(rows)


def main(argv=None):
    parser = argparse.ArgumentParser()
    parser.add_argument("folder", type=Path)
    parser.add_argument("--apply", action="store_true", help="really move the files")
    args = parser.parse_args(argv)
    if not args.folder.is_dir():
        print("Not a folder:", args.folder)
        return 1

    moves = plan_moves(args.folder)
    for source, destination in moves:
        print(f"  {source.name}  ->  {destination.parent.name}")
    if not args.apply:
        print(f"Dry run: {len(moves)} file(s) would move. Add --apply to do it.")
    elif moves:
        rows = apply_moves(moves)
        write_log(args.folder, rows)
        moved = sum(1 for row in rows if row["result"] == "moved")
        print(f"Moved {moved} of {len(rows)} file(s). A log was written in the folder.")
    else:
        print("Nothing to move.")
    return 0


if __name__ == "__main__":
    raise SystemExit(main())

plan_moves only looks. apply_moves checks destination.exists() first, because the documentation says rename silently replaces an existing file on Unix (macOS and Linux) but raises an error on Windows. write_log opens with "x", so it cannot overwrite a log. main uses argparse (standard library) to read your options and add --help.

Do the dry run on the practice folder first.

text · 8 lines
python tidy.py practice
  budget.CSV  ->  Data
  holiday.jpg  ->  Images
  logo.png  ->  Images
  notes.txt  ->  Documents
  readme  ->  Other
  scan.pdf  ->  Documents
Dry run: 6 file(s) would move. Add --apply to do it.

Nothing moved. When the plan looks right, add --apply. It ends Moved 6 of 6 file(s). A log was written in the folder. The files now sit in four sub-folders, and a tidy-log CSV records each move. To undo one, move it back by hand.

Try it yourself · Activity 05

20 min

Use it safely

Run the tool the careful way, then test its refusal to overwrite.

  1. Run python tidy.py --help and read it.
  2. Do the dry run on practice. Check nothing changed.
  3. Run with --apply and open the log.
  4. Copy any small file into practice as logo.png (for example cp hello.py practice/logo.png) and run --apply again.

Which design rule protected you?

Worked answer

--help lists the folder and --apply. The dry run changes nothing, and after --apply the log shows moved six times. The second logo.png is planned again, but the tool prints Moved 0 of 1 file(s) and the log says skipped: name already exists.

Next chapter

Learn in your browser · Chapter 06 of 06

06

Test it, review it, know your limits

A tool you have not tested is a tool you are hoping about. Add a first test, then learn to read code you did not write.

A unit test is a small program that checks one piece of code and reports pass or fail. Python includes unittest. Put tests in a file starting test, subclass unittest.TestCase and start each method name with test. These tests use tempfile.TemporaryDirectory(), a scratch folder that Python removes afterwards, so they never touch your real files. Save this as test_tidy.py beside tidy.py and run python -m unittest there.

python · 25 lines
import tempfile
import unittest
from pathlib import Path

import tidy


class TidyTests(unittest.TestCase):
    def test_group_for(self):
        self.assertEqual(tidy.group_for("Holiday.JPG"), "Images")
        self.assertEqual(tidy.group_for("readme"), "Other")

    def test_never_overwrites(self):
        with tempfile.TemporaryDirectory() as tmp:
            folder = Path(tmp)
            (folder / "Documents").mkdir()
            (folder / "Documents" / "a.txt").write_text("old", encoding="utf-8")
            (folder / "a.txt").write_text("new", encoding="utf-8")
            rows = tidy.apply_moves(tidy.plan_moves(folder))
            self.assertEqual(rows[0]["result"], "skipped: name already exists")
            self.assertEqual((folder / "Documents" / "a.txt").read_text(encoding="utf-8"), "old")


if __name__ == "__main__":
    unittest.main()

text · 5 lines
..
----------------------------------------------------------------------
Ran 2 tests in 0.015s

OK

Two dots mean two passes, and the time will differ.

Reading other people's code. Read before you run: the docstring, then the import lines, the function names and the bottom of the file. Then ask:

Scroll sideways to see every column.

Test it, review it, know your limits · Table 3
QuestionWarning sign
What does it read and change?Paths typed into the code, or your whole home folder
Can it delete or overwrite?unlink, rmtree, files opened with "w"
Is there a dry run?Nothing stops it acting first time
What if something fails?A bare except: that carries on
Does it run programs or text as code?subprocess, eval or exec

AI-written code. An AI assistant can explain a script line by line, add a dry run or suggest tests. But it writes plausible text, so its code can look tidy and still be wrong, use functions that do not exist or ignore your safety. Treat it as a draft from a fast stranger: read it, run it on copies and test it. Never paste passwords or other people's data into a prompt.

Here is a function of the kind you might be handed. Do not run it on real files.

python · 13 lines
def average_score(filename):
    try:
        f = open("C:\\Users\\sam\\scores.csv")
        rows = f.read().split("\n")
        total = 0
        for r in rows:
            total = total + int(r.split(",")[1])
        return total / len(rows)
    except:
        return 0


print(average_score("scores.csv"))

Try it yourself · Activity 06

30 min

Test it, then review it

Make a test fail on purpose, then review the function above.

  1. Run python -m unittest and confirm two passes.
  2. In tidy.py, change "Images" to "Pictures" for .jpg, run the tests and read the failure from the bottom. Then undo it.
  3. Add a third test method: group_for("archive.zip") is "Other".
  4. List four problems with the review function and say what it prints.

Which problem would be hardest to spot behind a confident AI explanation?

Worked answer

The change makes test_group_for fail with AssertionError: 'Pictures' != 'Images', ending FAILED (failures=1). The new test is a method such as def test_zip(self): with self.assertEqual(tidy.group_for("archive.zip"), "Other") indented beneath it, and the run reports Ran 3 tests. The review function prints 0: it ignores its argument, hard-codes a path, hides every error with a bare except:, never closes the file, and would choke on the header row.

Know your limits. You now have the basics, not a professional engineering education. Real projects need design, version control, review and upkeep. The official Python Tutorial assumes you have programmed before, and the Python Beginner's Guide points to resources for people who have not. Keep the habits: read first, dry run first, never delete, test.

Assessment options

Keep learning

The complete workbook

This workbook takes a complete beginner from installing Python to a small, tested tool that sorts and reports on a folder of files. You will learn variables, decisions, loops, functions, files, CSV and error handling, then add a dry-run habit and a first automated test. You will also practise reading other people's code, and AI-written code, with a critical eye.

  1. 01
    Install Python and run a script

    Install Python, try one line, then run a saved script.

    Read here · 1 exercise
  2. 02
    Values, decisions and loops

    Programs remember values, make decisions and repeat work. Learn these three and you can read most short scripts.

    Read here · 1 exercise
  3. 03
    Functions, files and paths

    Functions organise your work, and files and paths are how scripts touch the real world.

    Read here · 1 exercise
  4. 04
    Text, CSV and things going wrong

    Real data is messy, so learn to read files and to fail well.

    Read here · 1 exercise
  5. 05
    Build the folder tool, dry run first

    Combine everything into one tool that sorts a folder's files by type and reports what it did.

    Read here · 1 exercise
  6. 06
    Test it, review it, know your limits

    A tool you have not tested is a tool you are hoping about. Add a first test, then learn to read code you did not write.

    Read here · 1 exercise

Also inside: a 9-point checklist, a glossary of 12 terms and 10 questions and answers to test yourself. 6 hands-on exercises, each with a worked answer at the back where the workbook gives one.

The PDF is free. We ask for your name and email before downloading. Read the privacy notice at the download form. Free to download and use for personal learning, study groups and inside your own team. Please do not resell the workbooks or republish them as your own. Link people to trust-agent.ai instead.

Get your free PDF workbook

Enter your name and email, then download the complete workbook. This form also works without JavaScript.

We privately record your name, email and request IP for this download. Read our privacy notice and retention policy.

Visit Mickai on LinkedIn

Newsletter confirmation does not affect your download. Following Mickai on LinkedIn is optional; this site does not verify followers.

Test yourself

Questions and answers

Do I need maths or a computing background to learn Python?

Not to automate everyday tasks. If you can follow a recipe or a spreadsheet formula, you have enough to start. What you do need is patience with small errors, because everyone meets them, and the habit of reading error messages slowly.

Which version of Python should I install?

A current, supported one. The version status page on python.org lists which versions still receive fixes, and at the time of writing each is supported for five years. This workbook was tested on Python 3.12.10, and its examples use only the standard library.

My computer cannot find the python command. What now?

Try py on Windows or python3 on macOS and Linux. If neither works, repeat the installation using the current instructions on python.org and read any prompt about your PATH, the list of places your computer looks for programs.

How do I read an error message?

Start at the bottom. The last line of a traceback names the type of error and says what went wrong. The lines above show where in your code it happened. Read the message, find the line, and change one thing at a time.

What is a dry run and why should scripts default to one?

A dry run reports what a script would do without doing it. Defaulting to one means a mistake, a wrong folder or a misunderstood option costs you a printout instead of your files. The script acts only when you add a flag such as --apply.

Is it safe to run code that an AI assistant wrote?

Not automatically. Such code can look convincing and still be wrong. Read it, ask what it reads, changes and deletes, check for a dry run, try it on copies first and test it. Never paste passwords or other people's private data into a prompt.

Why write encoding and newline in open() calls?

Up to Python 3.14, the documentation says the default encoding depends on the platform, so naming utf-8 makes a script behave the same everywhere. For CSV files, the csv module's documentation says to open them with newline="" so line endings are handled correctly.

Do I need a test for a small script?

Not for a throwaway one. For anything that changes files, or that you will run again, yes. A test records what the script must never do, such as overwrite a file, and it tells you at once if a later edit breaks that promise.

Do I need to install extra packages?

Not for this workbook. It uses only the standard library: pathlib, csv, argparse and unittest all come with Python. Packages written by other people are code you did not write, so read about one and check it before you install it.

Does this workbook make me a software engineer?

No. It teaches the basics and one careful habit set. Professional engineering also involves design, version control, code review, security and long-term upkeep. Treat this as a solid first step and keep building small, safe tools.

Write as you go

My notes

Use this scratchpad for your own notes, working or answers as you read. Notes are saved in this browser on this device. Downloading makes a local copy; it does not send your notes to Mickai.

Consolidate your learning

Review your work

Work through the exercises and questions, then compare your reasoning with the worked answers. A scored exam and verifiable certificate are not yet available for this course.

Review the questions

Learn the language

Key terms

Script
A plain text file of Python instructions that the interpreter runs from top to bottom.
Interpreter
The program, started with python or python3, that reads Python code and carries it out.
Variable
A name attached to a value, such as price = 2.5.
Type
The kind of a value, such as text (str), whole number (int), decimal (float), list or dict.
Function
A named, reusable piece of code that takes inputs and can return a result.
Path
The location of a file or folder. The pathlib module handles paths for you.

6 of the workbook's 12 terms. The complete glossary is in the workbook.

Follow the evidence

Sources and checks

Facts last checked: .

Examples in this workbook were run on: Python 3.12.10 on Windows 11 (2026-09-26).

These workbooks use AI assistance. See how the workbooks are made.

  1. Using Python on WindowsPython Software Foundation
  2. Using Python on macOSPython Software Foundation
  3. Using Python on Unix platformsPython Software Foundation
  4. Download PythonPython Software Foundation
  5. Status of Python versionsPython Developer's Guide
  6. Using the Python interpreter (The Python Tutorial)Python Software Foundation
  7. Reading and writing files (The Python Tutorial)Python Software Foundation
  8. Errors and exceptions (The Python Tutorial)Python Software Foundation
  9. The Python TutorialPython Software Foundation
  10. Beginner's Guide to PythonPython Wiki
  11. Built-in functions (open, eval, exec)Python Software Foundation
  12. pathlib: object-oriented filesystem pathsPython Software Foundation
  13. csv: CSV file reading and writingPython Software Foundation
  14. sys: system-specific parameters and functionsPython Software Foundation
  15. argparse: parser for command-line optionsPython Software Foundation
  16. unittest: unit testing frameworkPython Software Foundation
  17. tempfile: temporary files and directoriesPython Software Foundation
  18. shutil: high-level file operationsPython Software Foundation
  19. subprocess: subprocess managementPython Software Foundation

Created by Mickarle Wagstaff-Irons - Micky Irons with the Mickai team. Published by Mickai LTD. Last updated 26 September 2026.

NextKeep going

Where to go next

Level 3Building 105 min

Build your first chatbot

Build a chatbot that behaves: model access, system prompt, history and context limits, guardrails, tone, a test set, logging and cost, on a no-code path or a code path.