DEV Community

ライフポータル
ライフポータル

Posted on • Originally published at code-izumi.com

Python Batch Processing: From .bat Integration to Subprocess Best Practices

In the world of data analysis and business automation, Python is a powerful tool for "batch processing." Whether it's automating repetitive tasks or processing heavy datasets overnight, the applications are endless.

However, "batch processing with Python" can mean different things depending on the context. Are you trying to trigger a Python script automatically? Do you want to call Python from a Windows batch file (.bat)? Or do you need Python to command other external programs?

In this article, we’ll dive into the essentials: integrating with Windows batch files, mastering the subprocess module, and exploring frameworks that scale for professional development.


Three Patterns of Python Batch Processing

Before coding, identify which pattern fits your needs:

  1. Pure Python Automation: Everything stays within Python (file I/O, scraping, etc.).
  2. Executing Python via Batch Files (.bat): Common for Windows Task Scheduler or quick desktop shortcuts.
  3. Running External Commands from Python: Using Python as a "commander" to trigger OS commands or other .exe files.

Method 1: Running Python Scripts from a .bat File

If you are on Windows, wrapping your script in a .bat file is the standard way to handle scheduled tasks. Here is how to write a robust batch file that doesn't break due to path issues.

The Basic Setup

Create a file named run.bat in the same directory as your script.py.

run.bat

@echo off
cd /d %~dp0
python script.py
pause
Enter fullscreen mode Exit fullscreen mode

Why this specific code?

  • @echo off: Cleans up the terminal output.
  • cd /d %~dp0: This is the most important line. It ensures the current directory is set to where the batch file is located. Without this, your script will likely fail with "File Not Found" errors when trying to read local files.
  • pause: Keeps the window open after execution. If the script crashes, you’ll actually be able to read the error message instead of the window vanishing instantly.

Using Virtual Environments (venv)

If your project relies on specific libraries, don't use activate.bat. It's cleaner to point directly to the python executable within your venv.

run_venv.bat

@echo off
cd /d %~dp0
.\venv\Scripts\python.exe script.py
pause
Enter fullscreen mode Exit fullscreen mode

Passing Arguments

You can pass parameters from the batch file to Python using sys.argv.

run_args.bat

@echo off
cd /d %~dp0
python script.py "test_data" 100
pause
Enter fullscreen mode Exit fullscreen mode

script.py

import sys

args = sys.argv
# args[0] is the script name. args[1] and onwards are your parameters.
print(f"File name: {args[0]}")

if len(args) > 1:
    print(f"Argument 1: {args[1]}")
    print(f"Argument 2: {args[2]}")
Enter fullscreen mode Exit fullscreen mode

Method 2: Controlling External Commands with subprocess

Sometimes, your Python script needs to call an external tool or a system command. While os.system was the old way, the subprocess module is the modern standard.

Using subprocess.run

This is the most common way to run a command and wait for it to finish.

import subprocess

# Running a 'dir' command on Windows
result = subprocess.run(["dir", "/w"], shell=True, capture_output=True, text=True)

print("--- Output ---")
print(result.stdout)
Enter fullscreen mode Exit fullscreen mode

Pro Tip: The shell=True Security Risk
You need shell=True for built-in Windows commands like dir or copy. However, for running .exe files or other scripts, keep it shell=False (default). Using shell=True with untrusted user input can expose your system to command injection attacks.

Error Handling

Always use check=True if you want your Python script to raise an exception if the external command fails.

import subprocess

try:
    # Attempting to run a non-existent command
    subprocess.run(["unknown_command"], shell=True, check=True)
except subprocess.CalledProcessError as e:
    print(f"Command failed with error: {e}")
Enter fullscreen mode Exit fullscreen mode

Professional Frameworks for Batch Processing

As your project grows, manual script management becomes a nightmare. Consider these tools:

1. The Standard Approach: argparse & logging

Don't use print() for batch logs. Use the logging module to manage error levels and argparse to create professional CLI help menus automatically.

2. Click: The Human-Friendly CLI Tool

Click is a third-party library that makes creating complex CLI commands intuitive using decorators.

import click

@click.command()
@click.option('--count', default=1, help='Number of greetings.')
@click.option('--name', prompt='Your name', help='The person to greet.')
def hello(count, name):
    for _ in range(count):
        click.echo(f"Hello, {name}!")

if __name__ == '__main__':
    hello()
Enter fullscreen mode Exit fullscreen mode

3. Workflow Management: Luigi & Airflow

For massive systems where "Task B" must wait for "Task A" to finish, look into Apache Airflow or Luigi. They provide GUIs to visualize your pipelines and handle retries automatically.


Troubleshooting Checklist

If your batch process fails, check these three common culprits:

  1. The "App Execution Alias" Trap: In Windows 10/11, typing python might open the Microsoft Store. Disable this in "Manage app execution aliases" in your Windows settings.
  2. Permission Issues: Scripts trying to write to C:\Program Files or system folders will fail without Administrator privileges.
  3. Character Encoding: If Japanese or special characters look like gibberish in the Windows console, force UTF-8 in your Python script:

    import sys
    sys.stdout.reconfigure(encoding='utf-8')
    

Conclusion

Building a batch process is easy, but building a reliable one requires attention to detail—especially regarding paths and error handling. Start with a simple .bat wrapper, and as your needs evolve, migrate to subprocess or a dedicated framework like Airflow.


Originally published at: [https://code-izumi.com/python/batch-processing/]

Top comments (0)