Automate Workflows with Python Scripts
Automate workflows with Python scripts — Python for data science tutorial, lesson 68.
Focus: automate workflows with python scripts
You've cleaned the data, built the model, and produced the perfect visualization — only to realize you have to re-run the whole pipeline every time a new CSV lands in your inbox. Manually executing python clean.py, then python model.py, then python report.py, juggling file paths and praying you didn't forget a step, is a recipe for errors and wasted hours. This lesson shows you how to automate workflows with Python scripts — stitching your data science steps into a single, repeatable, and reliable pipeline that runs at the click of a button (or on a schedule).
The problem this lesson solves
Data science isn't just analysis; it's a series of repeated tasks. Every new dataset, every updated report, every re-run of a model demands the same tedious sequence: load, clean, transform, train, output. Doing this manually is not only boring — it's dangerous. A forgotten step, a wrong file version, or an inconsistent order can silently corrupt your results.
The real pain points you've probably felt:
- Repetitive manual steps — typing the same commands over and over, copying files, and clicking through notebooks.
- Inconsistency — running scripts in slightly different orders across team members, producing inconsistent outputs.
- Time wasted — waiting around while data loads or models train, when you could be doing actual analysis.
- Error-prone environments — forgetting to activate the right virtual environment or install a dependency before running.
Automation with Python scripts solves all of this by encapsulating your workflow into a single, executable artifact. Instead of a collection of loose steps, you get a pipeline that anyone (including future you) can run with one command. This lesson is your step-by-step guide to building that pipeline.
Core concept / mental model
Think of your workflow as a factory assembly line. Each script is a workstation that takes an input, does a specific job, and passes the output to the next station. The overall process is orchestrated by a conveyor belt — your Python automation script — that ensures parts move smoothly from start to finish.
Key vocabulary:
- Workflow: A sequence of tasks to accomplish a goal (e.g., from raw data to final report).
- Automation: Replacing manual execution with a programmed trigger and sequence.
- Pipeline: The automated version of your workflow, often with defined stages and data handoffs.
- Orchestration: The coordination of when and how each step runs — our script's job.
Mental model in action: You have
process_data.py,train_model.py, andgenerate_report.py. Your automation scriptrun_pipeline.pybecomes the conductor: it calls each module in order, checks that every step succeeded, and logs progress. The result is a single command —python run_pipeline.py— that does everything.
This model applies across a spectrum: from a simple three-step script to a full ETL (Extract, Transform, Load) job that ingests data from a database, cleans it, and loads it into a warehouse. The principles are the same.
How it works step by step
Building an automated workflow with Python scripts involves a systematic approach. Here's the logical sequence:
1. Break your workflow into discrete steps
Identify each distinct task in your process. For a typical data science project:
- Extract: Read data from a source (CSV, API, database).
- Clean: Handle missing values, fix data types, remove duplicates.
- Transform: Create features, aggregate, merge.
- Model: Train and evaluate a machine learning model.
- Output: Generate a report, save a plot, export predictions.
Each step should be a separate, well-named script or a function within a module.
2. Build each step as a script with clear interfaces
Each script should do one thing well. It should read input from a defined location and write output to another defined location. This makes the steps reusable and testable.
3. Create a master script to orchestrate the sequence
This is your automation hub. It will:
- Import or call each step's main function.
- Pass the output of one step as input to the next.
- Handle errors and log progress.
The simplest version uses a series of function calls:
# run_pipeline.py
from pathlib import Path
from steps import extract, clean, transform, train, report
def run():
print("Pipeline started")
raw_path = Path("data/raw/data.csv")
clean_path = Path("data/clean/clean.csv")
features_path = Path("data/features/features.csv")
model_path = Path("models/model.pkl")
report_path = Path("reports/report.html")
extract.extract(raw_path) # Step 1
clean.clean(raw_path, clean_path) # Step 2
transform.transform(clean_path, features_path) # Step 3
train.train(features_path, model_path) # Step 4
report.generate(model_path, report_path) # Step 5
print("Pipeline completed successfully")
if __name__ == "__main__":
run()
4. Add error handling and logging
A robust automation script doesn't just fail silently. It logs where it went wrong so you can fix it quickly. Use Python's logging module.
5. Make it configurable
Hard-coding file paths is a quick way to make your pipeline fragile. Use configuration files (like YAML or JSON) or command-line arguments to make it flexible.
Hands-on walkthrough
Let's build a mini pipeline that reads a CSV, cleans it, and produces a summary report. We'll cover three versions: a simple sequential script, one with logging and error handling, and one that accepts command-line arguments.
Example 1: Sequential pipeline with logging
# simple_pipeline.py
import logging
import pandas as pd
from pathlib import Path
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def extract(file_path):
logging.info(f"Extracting data from {file_path}")
return pd.read_csv(file_path)
def clean(df):
logging.info("Cleaning data: dropping rows with missing 'sales'")
return df.dropna(subset=['sales'])
def summarize(df, output_path):
logging.info("Generating summary report")
summary = df.groupby('region')['sales'].sum().reset_index()
summary.to_csv(output_path, index=False)
logging.info(f"Summary saved to {output_path}")
def run(input_file, output_file):
raw_df = extract(input_file)
clean_df = clean(raw_df)
summarize(clean_df, output_file)
logging.info("Pipeline complete")
if __name__ == "__main__":
run("data/raw/sales.csv", "data/output/sales_summary.csv")
Expected output (console log):
2025-01-01 10:00:00 - INFO - Extracting data from data/raw/sales.csv
2025-01-01 10:00:01 - INFO - Cleaning data: dropping rows with missing 'sales'
2025-01-01 10:00:01 - INFO - Generating summary report
2025-01-01 10:00:02 - INFO - Summary saved to data/output/sales_summary.csv
2025-01-01 10:00:02 - INFO - Pipeline complete
Example 2: Adding error handling and a config file
# configurable_pipeline.py
import json
import logging
import pandas as pd
from pathlib import Path
from datetime import datetime
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
def load_config(path):
with open(path) as f:
return json.load(f)
def extract(file_path):
logging.info(f"Extracting from {file_path}")
if not Path(file_path).exists():
raise FileNotFoundError(f"Data file not found: {file_path}")
return pd.read_csv(file_path)
def run(config):
try:
raw = extract(config['input_file'])
clean = raw.dropna()
clean.to_csv(config['output_file'], index=False)
logging.info("Pipeline successful")
except Exception as e:
logging.error(f"Pipeline failed: {e}")
raise
if __name__ == "__main__":
cfg = load_config("config.json")
run(cfg)
Example config.json:
{
"input_file": "data/raw/data.csv",
"output_file": "data/clean/clean.csv"
}
Expected behavior: The script reads configuration, runs the pipeline, and logs success or error.
Example 3: Command-line arguments for maximum flexibility
# cli_pipeline.py
import argparse
import pandas as pd
def main():
parser = argparse.ArgumentParser(description='Run data pipeline')
parser.add_argument('--input', required=True, help='Input CSV path')
parser.add_argument('--output', required=True, help='Output CSV path')
args = parser.parse_args()
df = pd.read_csv(args.input)
df.dropna(inplace=True)
df.to_csv(args.output, index=False)
print(f"Processed {len(df)} rows -> {args.output}")
if __name__ == "__main__":
main()
Run it from the shell:
python cli_pipeline.py --input data/raw/data.csv --output data/clean/clean.csv
Expected output: Processed 950 rows -> data/clean/clean.csv
Compare options / when to choose what
You have several ways to automate your workflows. Here's a comparison to help you decide.
| Approach | Pros | Cons | Best for |
|---|---|---|---|
| Single Python script | Simple, no extra dependencies, easy to start | Not scalable for huge projects, limited scheduling | Small projects, prototyping |
| Python module with orchestration script | Modular, reusable, clean code | Slightly more setup | Medium projects, teams |
Use snakemake or luigi |
Built-in dependency management, parallel execution | Learning curve, extra dependencies | Complex pipelines with many dependencies |
cron or Task Scheduler (run scripts automatically) |
No need to run manually, scheduled | No built-in error handling, system-specific | Recurring scheduled jobs |
| Full workflow managers (Airflow, Prefect) | Powerful, production-ready, UI | Heavyweight, overkill for small tasks | Enterprise data pipelines, orchestration |
Decision rule: Start with a simple script. If your workflow grows to more than 5 steps or requires frequent re-runs, move to an orchestration tool. Use
crononly for fire-and-forget jobs where failures aren't critical.
Troubleshooting & edge cases
Automation scripts often fail in predictable ways. Here are common issues and fixes:
- Error:
FileNotFoundError— Your script expects a file that doesn't exist. Always usePathobjects and check existence before reading. Or usetry-exceptto catch it. - Error: pandas
KeyErroron column — Column names might have spaces or case differences. Usedf.columnsto inspect, or normalize columns at the beginning:df.columns = [c.lower().strip() for c in df.columns]. - Script runs but produces empty output — Your cleaning step might drop all rows. Log the number of rows before and after each step:
logging.info(f"Rows: {len(df)}"). - Scheduling with cron/Windows Task Scheduler fails silently — Ensure you use the full path to the Python executable and the script. Also capture output to a log file:
python /path/to/script.py >> /path/to/log.txt 2>&1. - Environment differences — Script works on your machine but not on the server. Always define
requirements.txtand use virtual environments. Consider usingpip freeze > requirements.txt. - Path issues on Windows vs. Unix — Use
pathlib.Pathinstead of hard-coded path strings; it's cross-platform.
What you learned & what's next
You now understand how to automate workflows with Python scripts: breaking tasks into modular steps, orchestrating them with a master script, adding logging and error handling, and making your pipeline configurable. You can apply this to your own data science projects to save time and reduce mistakes.
You've also learned to evaluate different automation approaches, from simple scripts to full workflow managers, and you know how to troubleshoot common pitfalls.
What's next? In the next lesson, you'll build on this foundation by exploring how to schedule your automated workflows using cron jobs or cloud schedulers — taking your scripts from run-when-you-remember to run-on-time, every time. You'll also learn to monitor and alert on failures in production.
Practice recap
Take one of your existing data science scripts that has multiple steps (e.g., load, clean, plot) and refactor it into a single automation script with at least three separate functions. Add logging to show progress and an error handler that gracefully exits if a required column is missing. Then, run it from the command line using a config file or CLI argument for the input path. This will give you hands-on experience in building a reusable, automated workflow.
Common mistakes
- Hardcoding absolute file paths like
C:/Users/...instead of usingpathlib.Pathor relative paths, making the script break on another machine. - Forgetting to handle missing files or exceptions, so the pipeline fails with a cryptic traceback halfway through.
- Running scripts manually and skipping the orchestration step, leading to inconsistent data or forgotten steps.
- Not logging progress, making it impossible to know which step failed when the script errors out.
- Using
print()for debugging instead of theloggingmodule, which is hard to redirect or filter in production.
Variations
- Use
snakemakefor rule-based pipelines that automatically resolve dependencies and can run tasks in parallel. - Use
luigifor a more code-centric pipeline that handles task dependencies and has visualization tools. - Use
cron(Unix) or Task Scheduler (Windows) to run your Python scripts automatically at set times, perfect for nightly data refreshes.
Real-world use cases
- Automating a nightly ETL job that extracts sales data from a database, cleans it, and loads it into a data warehouse for reporting.
- Building a data cleaning pipeline that processes incoming CSV files from clients, standardizes columns, and outputs merged, deduplicated data for analysis.
- Automating model retraining after new data arrives: a script that pulls fresh data, trains a new model, and saves it for the next day's predictions.
Key takeaways
- Automation turns a manual sequence of steps into a single, repeatable Python script.
- Break your workflow into modular steps with clear inputs and outputs for reusability.
- A master orchestration script coordinates your steps, handling errors and logging.
- Use command-line arguments or config files to make your pipeline flexible and environment-agnostic.
- Choose the right automation level: simple script for small tasks, workflow managers for complex dependencies.
- Logging is essential for debugging and monitoring automated pipelines.
Keep learning
Related tutorials, quizzes, and articles for this topic.
Discussion
Questions, corrections, and tips help everyone reading this page.
0 comments
Add a comment
No comments yet — start the thread.