【问题标题】:Testing Django commands file or stdin测试 Django 命令文件或标准输入
【发布时间】:2017-02-14 00:36:09
【问题描述】:

我正在编写一个 django 命令,它需要大量输入并对其进行处理。

由于数据量大,输入应该以文件或标准输入的形式出现,这似乎很自然。

我想轻松地对其进行测试,我的意思是说,无需在我的测试环境中创建一堆文件。

现在,我记得某处(找不到正确的文档,but I did find the "PR"),“-”应该从标准输入读取,但我无法让它工作。

似乎该命令应该执行以下操作:

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

但是当我在命令行上运行命令时,它不喜欢- 参数(说它不是文件)。

command docs 建议写信给self.stdout 以获得更好的测试。我为 self.stdin 尝试了类似的方法,但也无法正常工作。

当然,这是一种常见的模式,但我找不到任何关于如何做到最好的帮助。似乎“应该有一种——最好只有一种——明显的方法。”,但我找不到。我有什么遗漏吗?

【问题讨论】:

  • 如果能解决问题,我会创建一堆文件作为我的测试夹具。我不认为这种方式不好
  • 你是如何编写测试的? “-”在哪里?
  • @Ming 我希望我的测试很简单,所以它们大多只是其中只有一行的文件,甚至是一个单词,而且不得不去查看文件似乎很烦人看看里面有什么。通过单个项目的测试似乎更干净。
  • @Ming 我对“-”的测试是在命令行上运行的(编辑问题以更好地反映这一点)

标签: python django django-commands


【解决方案1】:

Django 命令参数解析器是argparse 模块的包装。根据这篇文章:Optional stdin in Python with argparse,您可以定义一个参数来接受stdin 或实际文件作为输入。

示例命令供您参考:

管理/命令/stdintest.py

from django.core.management.base import BaseCommand
import sys
import argparse


class Command(BaseCommand):
    help = 'Test stdin as input file'

    def add_arguments(self, parser):
        parser.add_argument('foo', nargs='?', type=argparse.FileType('r'), default=sys.stdin)

    def handle(self, *args, **options):
        foo = options.get('foo')
        sys.stdout.write(foo.read())

可以在不指定输入文件的情况下调用该命令,该命令会从标准输入中抓取输入

$ python manage.py stdintest
1234
abcd     <- press ctrl+d to end stdin input
1234
abcd

或使用实际文件指定 foo 参数

$ echo '12345' > test.txt
$ python manage.py stdintest test.txt

我不确定这是否是您所需要的。如果我误解了,请发表评论。希望它会有所帮助。

【讨论】:

  • 这很有帮助,谢谢,但另一个答案比我要求的要多一些。
【解决方案2】:

查看 the docstype= add_argument 参数,它说“argparse 模块提供工厂 FileType”。

所以我做了以下操作,./manage.py test_stdin - 然后按照您的预期工作。

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))

【讨论】:

  • 这很棒。谢谢。 argparse.FileType('r') 不是很直观。我(显然)希望有像file 这样更简单的东西。谢谢。
  • 这是因为 file 没有对 '-' 进行特殊处理,而查看 argparse 的源代码时,它会检查 if string == '-' 并在模式为 'r' 时返回标准输入。当您意识到“-”是可执行参数而不是其他地方的约定时,这是有道理的。但是感谢您的接受,解决这个问题很有趣。
猜你喜欢
  • 1970-01-01
  • 2014-02-02
  • 2017-03-04
  • 2011-12-13
  • 2014-08-05
  • 1970-01-01
  • 2021-04-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多