Course Content
Module 1 – Getting Started with Python
introduced the fundamentals of Python, giving beginners a clear understanding of how the language works and how to start writing simple programs. Python was highlighted as a beginner-friendly language with simple syntax, making it easy to read and write code.
0/7
Module 2 – Introduction to Python Programming
In this Introduction to Python module, learners explore Python’s clear, readable syntax and powerful features. Beginning with installation and a simple “Hello, World!” script, you will progress through variables, control flow and functions using step-by-step examples. By the end, you will be equipped to write your own Python programmes, automate routine tasks and tap into an extensive library ecosystem for real-world projects.
0/7
Basic Command for Command prompt, PowerShell, Zsh(macOS)
0/1
Module 3 – Variables, Data Types and Basic Operations
In the Variables, Data Types and Basic Operations in Python module, learners explore how to store and manage data using variables, master fundamental types such as integers, floats, strings and booleans, and perform arithmetic, comparison and logical operations step by step. Clear explanations, real world examples and hands on exercises guide you through writing and debugging code. By the end of this module, you will be ready to build dynamic Python programs and automate everyday tasks.
0/6
Module 4 – Control Flow – Conditions and Loops
Control flow structures determine the order in which your program’s code executes. With conditional statements, you can make decisions and execute certain code blocks only when specific conditions are met. Loops allow you to repeat actions efficiently without writing redundant code. In this module, we will explore fundamental control flow concepts in Python in a step-by-step manner, similar to Microsoft’s learning curriculum. By the end, you’ll understand how to use if, elif, and else statements (including nested conditions) for decision-making, how truthy and falsy values work in Boolean logic, how to construct for loops (using range() and iterating over collections), how to use while loops along with loop control statements (break and continue), and how to leverage list comprehensions and generator expressions for concise looping. Finally, we’ll apply these concepts in a practical exercise to build an interactive decision-making system. Each section below includes explanations, code examples, and mini-exercises to reinforce the concepts, all formatted for clarity and easy follow-along.
0/8
Day 1 Summary
We covered Modules 1, 2 & Module 3 (Lesson 1 & 2)
0/1
Module 5 – Functions and Code Organisation
Imagine you need to clean up a messy data set or send a personalised email to each customer. Instead of writing the same steps over and over, you can create a function and call it whenever you need. In this lesson on Functions and Code Organisation, you will learn how to define functions, pass and return information, document your work and group related code into modules for easy reuse and maintenance.
0/10
Day 2 Summary
Summary for Day 21 Aug 2025
0/1
Day 3 Summary
Summary of Day 28 Aug 2025
0/1
Module 7 – Working with Files and Folders
In this lesson, we will learn how to manipulate files and directories using Python. We’ll explore common file operations using the os module, and see how the pathlib module provides an object-oriented way to handle file paths. We’ll also use the glob module for pattern-based file searches and learn file I/O operations for text, CSV, and binary files. Additionally, we’ll introduce the calendar and time modules to work with dates and timestamps. Finally, an interactive lab will tie everything together by automating a folder backup and cleanup task. Follow the step-by-step sections below for each subtopic, try out the code examples, and explore the guided lab at the end.
0/9
Module 8 – Error Handling and Debugging Techniques
In this lesson, we will learn how to handle errors in Python programs and how to debug code effectively. Errors are inevitable, but knowing how to manage them ensures our programs don't crash unexpectedly. We will cover the difference between syntax errors and exceptions, how to use try, except, else, and finally blocks to catch and handle exceptions, and how to raise your own exceptions (including creating custom exception classes). We’ll also explore debugging strategies: using simple print statements or the logging module to trace your program’s execution, and using Python’s interactive debugger pdb to step through code. By following best practices for error handling and debugging, you can write resilient, maintainable code. Throughout this lesson, try the examples and exercises to practice these techniques.
0/9
Day 4 Summary
0/1
Module 9 – Automating Excel and PDFs with Python
In this lesson, you will learn how to automate common communication and reporting tasks using Python. We will cover sending notifications via email, messaging platforms, and SMS, as well as manipulating Excel spreadsheets and PDF files programmatically. Each section below includes step-by-step explanations, code examples, and interactive exercises to reinforce your understanding. By the end of this lesson, you’ll be able to send emails with attachments, integrate with Slack/Microsoft Teams, send SMS alerts, and automate Excel/PDF workflows.
0/9
Day 5 Summary
0/1
Mini Project: Build your own Automation Tool
The project incorporates two common automation tasks – Contact Management and Student Tasks Tracking
0/2
Day 6 Summary
0/1
Introduction to Python Programming (Copy 1)

Lab Activity: Automate Backup and Cleanup of a Target Folder

Objectives:

  • Practice working with file system operations in Python using os and pathlib.

  • Learn how to generate timestamped folder names with the time module.

  • Implement file copying using binary read/write operations.

  • Understand how to automate cleanup by deleting or moving files after backup.

  • Reinforce concepts of iteration, exception handling, and safe file handling in automation tasks.

In this lab, we will apply what we’ve learned to create a simple automation script. The goal is to back up all files from a target directory into a new folder (with a timestamped name), and then optionally clean up the original files. This simulates a backup rotation or cleanup task that might be scheduled to run periodically.

Scenario: Imagine you have a folder called “target_folder” that accumulates files (for example, daily reports or logs). You want to write a Python program that:

Creates a backup folder named with the current date/time.

Copies all files from target_folder into the backup folder.

(Optional) Deletes the original files in target_folder once backed up, or perhaps deletes only files older than a certain date (for safety, we will delete them in this lab to simulate a cleanup).

Follow the steps below to create this automation. (This can be done as a standalone script. Ensure you have a test directory with some sample files to try it out.)

step-by-step Instructions:

Step 1: Setup Paths and Timestamp

Decide on your target directory path. For example, you might have it as a Path or string. Let’s assume the target folder is “target_folder” in the current working directory.

Determine a name for the backup directory using the current timestamp. We can use the time module to get a timestamp string.

import os, time
from pathlib import Path

# Define the target directory and backup directory name
target_dir = Path("target_folder")
# Ensure the target folder exists
if not target_dir.exists():
    print(f"Target folder {target_dir} not found!")
    exit(1)

# Create a timestamped folder name, e.g., "backup_20250806_232045"
timestamp = time.strftime("%Y%m%d_%H%M%S")  # format: YYYYMMDD_HHMMSS
backup_dir = Path(f"backup_{timestamp}")
print("Backup directory will be:", backup_dir)

We used Path for convenience. We check if target_folder exists; if not, exit or handle accordingly.

time.strftime(“%Y%m%d_%H%M%S”) gives a string like 20250806_232045 for August 6, 2025 23:20:45. We prepend “backup_” to form the backup folder name.

We print the name to verify. (In a real script, you might log this or omit the print.)

Step 2: Create the Backup Directory

Next, create the backup directory on disk. Use os.mkdir() or Path.mkdir().

It’s good to handle the case that the directory might already exist (though with a timestamp, it’s unlikely to collide).

# Create the backup directory
backup_dir.mkdir(exist_ok=True)

Using exist_ok=True prevents an error if, by chance, a folder with the same name exists (perhaps from a run in the same second).

Step 3: Copy Files to the Backup

We need to copy all files from target_folder into backup_dir.

We can use the glob module or Path.iterdir() to get all files. Let’s use iterdir() for simplicity.

For each file, open it in ‘rb’ (read binary) and create a new file in backup_dir with the same name in ‘wb’ (write binary), then copy bytes.

for item in target_dir.iterdir():
    if item.is_file():
        # Construct corresponding path in backup_dir
        dest_file = backup_dir / item.name
        # Copy file contents
        with open(item, 'rb') as src, open(dest_file, 'wb') as dst:
            # read and write in chunks
            while chunk := src.read(4096):
                dst.write(chunk)
        print(f"Copied {item.name} to {dest_file}")

Explanation:

We loop through each item in the target directory.

Check item.is_file(). We skip subdirectories in this simple scenario. (If your target can have subfolders and you want to include them, you’d need a recursive copy approach or use shutil.copytree. But here we assume a flat structure in the target for simplicity.)

dest_file = backup_dir / item.name creates the new file path inside the backup directory with the same filename.

We open the source file in binary read and the destination in binary write. Then we read in chunks of 4096 bytes and write those chunks to the new file. This ensures even large files are handled without reading everything into memory at once.

After the loop, each file from the target should be duplicated in the backup folder. We print a message for each to confirm.

(Alternatively, we could have used shutil.copy2(item, dest_file) to copy files with metadata preserved, but doing it manually as above demonstrates the file handling concepts and uses binary mode reading/writing.)

Step 4: Clean Up Original Files (Careful!)

After successfully copying, if the goal is to remove the originals (to clean up space or avoid duplication), we can delete them. This step is irreversible, so in a real script ensure your backup is verified before deleting originals.

We can simply use os.remove() or Path.unlink() to delete each file.

Code (continuing from above):

        # After copying, delete the original file (optional cleanup)
        try:
            item.unlink()  # equivalent to os.remove(item)
            print(f"Deleted original {item.name}")
        except Exception as e:
            print(f"Could not delete {item.name}: {e}")

We put this in the same loop right after copying each file. We use Path.unlink() which removes the file. We wrap in try/except to handle any unexpected errors (like permission issues) – in a robust script you might handle those differently or log them.

Important: Only do this if you’re sure the backup succeeded. In our code, if an error occurs during copy (for instance, read error), the script would break out and not reach deletion. If you wanted to be extra safe, you could first collect all file paths, copy everything, verify, then if all good, loop again to delete. But for this exercise, we proceed as above for simplicity.

Step 5: Verify the Backup

It’s good practice to verify that the backup files exist and possibly have the same size as the originals. While not writing full verification code here, you can do a quick check:

for item in backup_dir.iterdir():
    print(item.name, "-", item.stat().st_size, "bytes")

Also, check that the target directory is now empty (if you deleted everything). You could print a message if list(target_dir.iterdir()) is empty, indicating cleanup done.

This verification could also involve checking the count of files, etc., but manual observation can suffice for now.

Running the Lab Script

If you run the combined code (Steps 1–4 in one script) on a test folder, you should see output like:

Backup directory will be: backup_20250806_232045
Copied report1.txt to backup_20250806_232045/report1.txt
Deleted original report1.txt
Copied report2.txt to backup_20250806_232045/report2.txt
Deleted original report2.txt
Copied image.png to backup_20250806_232045/image.png
Deleted original image.png

After running, target_folder would be empty (files removed) and a new folder backup_20250806_232045 would contain the files that were in target_folder. The timestamp ensures each backup run creates a new directory and doesn’t overwrite previous backups.

Clean Up Strategy Variations:

Instead of deleting files, you could move them. Using os.rename(item, dest_file) could move the file into the backup folder (which is effectively a cut-and-paste). That’s even simpler and ensures the backup has the file (since it’s literally the same file moved). However, moving is not copying – if the intention is to keep an original and have a copy, use copy + delete.

You might want to only delete files older than a certain age. You could check file modification times via os.stat(item).st_mtime (or item.stat().st_mtime with pathlib) and compare with the current time.

You could compress the backup folder into a zip file using Python’s shutil.make_archive or zipfile module if desired, instead of just copying to a folder.

For now, our lab accomplishes a basic backup and cleanup. It uses:

  • os/pathlib for filesystem operations.

  • time. strftime for timestamp in naming.

  • file reading/writing in binary mode to handle any file type.

  • optionally os.remove (via Path.unlink) for cleanup.

This automation can be run manually or scheduled (with Windows Task Scheduler, cron on Linux, etc.) to periodically archive files from a directory.