, ,

Automate a Task With a Python Script (Python for Beginners, Part 17)

Turn your code into an unattended script with the main guard, summarise saved data, and schedule it with cron or Task Scheduler without hitting the path trap.

Python for Beginners · Part 17 of 20

Automation is not a grand thing. It is a script that does a whole job on its own, start to finish, with nobody typing anything, so a computer can run it while you sleep. You already have the pieces. This part joins them into one program that summarises your spending, then hands that program to your operating system to run on a schedule.

Start hereAn automation is a plain script written to run unattended. You wrap the work in a main function, guard it with if __name__ == '__main__': so the file can be both imported and run, make sure it needs no typed input, then schedule it with cron on macOS or Linux, or Task Scheduler on Windows. That is the whole idea, and everything below fills it in.

This part pulls together files from Part 11, JSON from Part 16, and dates from Part 13. You need Python 3 and about thirty minutes. The scheduling piece touches your operating system, so the exact command differs by platform and both are shown.

The line that makes a file runnable

You have run scripts since Part 2, but there is one idiom every real script uses that we have skipped until now. It looks strange and it earns its place:

python
def main():
    print('summary would run here')

if __name__ == '__main__':
    main()

Python sets a hidden variable __name__ for every file. When you run a file directly, its __name__ is the text '__main__', so the guarded line is true and main runs. When another file imports this one, __name__ is the module’s name instead, the guard is false, and main does not fire. That single check lets a file be both a runnable script and a reusable module, and you will see it at the bottom of almost every Python program you meet.

How the file is usedValue of __name__Does main() run?
You run it directly'__main__'Yes
Another file imports itThe module nameNo

Table 1. Why the main guard runs your code only when the file is the one being run.

A script that summarises the spending

Here is the first real automation for the tracker. It loads the saved expenses, groups them by month, and prints a total for each. Because the project stamped each expense with a date back in Part 13, grouping is a matter of reading the first seven characters of the date, the year and month. It takes no input, which is what makes it safe to run unattended.

monthly_summary.py
import json
from collections import defaultdict

def load(path='expenses.json'):
    with open(path) as f:
        return json.load(f)

def monthly_totals(expenses):
    totals = defaultdict(float)
    for e in expenses:
        month = e['date'][:7]
        totals[month] += e['amount']
    return totals

def main():
    expenses = load()
    totals = monthly_totals(expenses)
    for month in sorted(totals):
        print(f'{month}  {totals[month]:>10.2f}')

if __name__ == '__main__':
    main()
output
2026-06      210.00
2026-07      160.50

The defaultdict(float) is a small convenience from the standard library: a dictionary that starts any new key at 0.0, so you can add to a month’s total without checking whether you have seen it before. Everything else is the file and JSON work you already know, arranged so the program runs once and finishes with a clear result on screen.

Handing the script to a scheduler

A script that runs itself is only automated once something triggers it without you. That something is a scheduler built into your operating system. On macOS and Linux it is cron; on Windows it is Task Scheduler. A cron entry is one line: five time fields, then the command. This one runs the summary at nine every morning:

crontab (macos / linux)
0 9 * * * /home/asha/tracker/.venv/bin/python /home/asha/tracker/monthly_summary.py

You add it by running crontab -e, pasting the line, and saving. On Windows, you open Task Scheduler, create a basic task, set a daily trigger, and point it at your Python and script. Same idea, different door.

9:00 each day monthly_summary runs itself a fresh summary cron triggers

Figure 1. The scheduler fires on a timer, the script runs unattended, and you get output without lifting a finger.

Gotcha: cron does not know your setupA script that works in your terminal often fails under cron with a familiar last line:
output
FileNotFoundError: [Errno 2] No such
file or directory: 'expenses.json'
cron starts in a bare environment. It does not activate your virtual environment and it does not run from your project folder, so a relative path like expenses.json is not found. The fix is to use full paths everywhere, both to the venv’s Python and to your data files, exactly as the cron line above does. Relative paths are the single most common reason a working script breaks once scheduled.

Keep the first automation small

There is a temptation, once you can schedule things, to reach for a heavy workflow tool with dashboards and retries for what is really a nightly one liner. Resist it at this stage. A plain script triggered by cron is enough for the vast majority of small automations, and it is far easier to understand and fix at two in the morning than a framework you half configured. Reach for the big tools when you genuinely have many dependent steps that must coordinate, not before.

Two habits make an unattended script trustworthy. Make it safe to run twice, so a repeat run does not double count or corrupt data, which is called being idempotent. And have it write a short line to a log file each time it runs, so when you wonder later whether it ran at all, the answer is written down. Those two habits cost a few lines and save whole evenings.

Why this matters on the jobA large slice of practical programming is unattended scripts: nightly reports, data imports, cleanup jobs, health checks. The skill of writing a script that takes no input, uses absolute paths, and runs cleanly under a scheduler is exactly what turns a useful snippet into something a team can rely on. Engineers who understand why cron cannot find their file, and fix it with full paths, save everyone the recurring three in the morning surprise.
Real interview question"What does if __name__ == '__main__': do?" A clean answer: it checks whether the file is being run directly, in which case __name__ is '__main__' and the block runs, or being imported, in which case it does not. It lets a file work as both a runnable script and an importable module. Being able to explain it plainly is a small but reliable signal that you have written real scripts, not just snippets.
Try it yourselfWrite a script that defines a greet function returning the text ready to run, then prints it only when the file is run directly, using the main guard. Expected output when you run the file:
expected output
ready to run
Show solution
python
def greet():
    return 'ready to run'

if __name__ == '__main__':
    print(greet())

Run the file and it prints; import it into another file and the print stays silent, because the guard is only true for the file you run directly.

Questions about automating your scripts

Do I always need the main guard? Not for a one off you run by hand, but get into the habit. The moment another file imports yours, the guard is what stops your whole script running as a side effect.

Why use the full path to python in cron? So the scheduler uses your project’s virtual environment, with its installed packages, instead of some other Python that lacks them. The path to .venv/bin/python pins the exact interpreter.

How do I pass an input to a scheduled script? You do not type it; you bake it in, read it from a file, or accept it as a command line argument through sys.argv. Unattended means no prompts.

Where does the output go when cron runs it? Nowhere visible by default. Redirect it to a file in the cron line, or have the script write its own log, so you can see what happened.

Is Windows Task Scheduler as capable as cron? For this purpose, yes. It triggers a program on a schedule just the same. The concepts match; only the interface differs.

Passing an argument on the command line

Unattended does not mean fixed forever. A scheduled script often needs one small piece of input, like which month to summarise, and you supply it on the command line rather than by typing at a prompt. Python hands you the words from the command line in a list called sys.argv:

monthly_summary.py
import sys

def main():
    if len(sys.argv) > 1:
        month = sys.argv[1]
    else:
        month = 'all'
    print(f'summarising: {month}')

if __name__ == '__main__':
    main()
terminal
python monthly_summary.py 2026-07
output
summarising: 2026-07

The list sys.argv holds the words you typed. The first entry is the script name itself, and everything after it is an argument you passed. Checking the length before reading sys.argv[1] avoids an IndexError when no argument is given, and a sensible default keeps the script working whether or not you supply one.

EntryHolds
sys.argv[0]The script name itself
sys.argv[1]The first argument you passed
sys.argv[2]The second argument, and so on

Table 2. What the command line arguments land in when your script starts.

One thing to remember: every entry in sys.argv is text, even a number, so convert with int() or float() before doing maths on it, the same lesson as reading from a file. When a script grows past a couple of options, the standard argparse module gives you named flags, help text, and validation for free, and it is the natural next step once bare sys.argv starts to feel fiddly.

In practiceScheduled jobs commonly take a date, a folder, or a mode as an argument, so one script serves many cases instead of being copied and edited for each. A little argument handling is what makes an automation flexible without ever needing someone at the keyboard.
You can nowYou can now write a script that runs itself end to end, guard it with if __name__ == '__main__':, group and summarise saved data, and schedule the whole thing with cron or Task Scheduler while avoiding the relative path trap that breaks scheduled jobs. Your tracker produces a monthly summary on its own. In Part 18 you make it trustworthy, with debugging habits and a couple of small tests.
schedulercron or Task Schedulersummary.pyexpenses.jsonread, then print totals
A scheduler runs the script on its own, which reads saved data and prints the summary.
Python for Beginners · Part 17 of 20
« Previous: Part 16  |  Complete Guide  |  Next: Part 18

About The Author


Discover more from Journal of Intelligent Infrastructure – By Dr Pranay Jha

Subscribe to get the latest posts sent to your email.

Leave a Reply

Your email address will not be published. Required fields are marked *

Architect’s Toolkit

About the Author

Dr. Pranay Jha is a Cloud and AI Consultant with 18+ years of experience in hybrid cloud, virtualization, and enterprise infrastructure transformation. He specializes in VMware technologies, multi-cloud strategy, and Generative AI solutions. He holds a PhD in Computer Applications with research focused on Cloud and AI, has published multiple research papers, and has been a VMware vExpert since 2016 and a VMUG Community Leader.

Discover more from Journal of Intelligent Infrastructure - By Dr Pranay Jha

Subscribe now to keep reading and get access to the full archive.

Continue reading