Here’s a little approach I’ve started using when writing Python scripts and Django console commands. It allows them to easily handle i/o from the commandline or from a file without much effort.

Rather than using sys.stdin or sys.stdout directly, you define an argparse.FileType argument for the command, and set the default to sys.stdin.

For example, in a Django command:

from sys import stdin, stdout
from argparse import FileType
from django.core.management.base import BaseCommand

class Command(BaseCommand):

default=stdin)
default=stdout)

def handle(self, *args, **options):
input = options['input']
output = options['output']
# ...


Now the command is flexible as you can pipe data to or from it:

cat input-file.txt | ./manage.py foo_command > output-file.txt


Or just tell it the names of files to use:

./manage.py foo_command input-file.txt output-file.txt


This makes the command easier to use in a variety of situations. It also has the benefit that when writing a test for a Django command, it’s easier to pass the input data than if it was using sys.stdin directly:

from io import StringIO
from django.core.management import call_command
from django.test import TestCase

class FooCommandTest(TestCase):

def test_foo_command(self):
out = StringIO()
input = 'path-to-some-file.txt'
call_command('foo_command', input, stdout=out)
# ...


This is a handy approach for testing commands that usually take their input from stdin.