pythondjangodjango-commands

Testing Django commands file or stdin


I am writing a django command that takes a bunch of input and processes it.

It seems natural that because of the volume of the data, the input should either come in as a file or as stdin.

I would like to easily test it, and by easily, I mean, without having to create a bunch of files in my test environment.

Now, I remember somewhere (can't find it properly documented, but I did find the "PR"), that the "-" is supposed to read from stdin, but I can't get it to work.

It seems the command should do something like this:

class Command(BaseCommand):
    def add_arguments(self, parser):
        parser.add_argument("foo", type=file)

    def handle(self, *args, **options):
        file = options["foo"]
        # Then read the file, and process it

But then when I run the command on the command line, it doesn't like the - parameter (says it isn't a file).

The command docs recommend writing to self.stdout for better testing. I tried something similar for self.stdin but couldn't get that to work either.

Assuredly this is a common pattern, but I couldn't find any good helps on how to do this best. It seems like "There should be one-- and preferably only one --obvious way to do it.", but I can't find it. Is there something I'm missing?


Solution

  • Having a look at the docs for the type= argument to add_argument, it says "the argparse module provides the factory FileType".

    So I did the following and ./manage.py test_stdin - then worked as you'd expect.

    import argparse
    
    class Command(BaseCommand):
        def add_arguments(self, parser):
            parser.add_argument("foo", type=argparse.FileType('r'))
    
        def handle(self, *args, **options):
            input_file = options["foo"]
            while True:
                line = input_file.readline()
                if len(line.strip()) == 0:
                    break
                else:
                    self.stdout.write("I just read %d chars, line %s" % (len(line),line))