[英]Spurious newlines added in Django management commands
Running Django v1.10 on Python 3.5.0: 在Python 3.5.0上运行Django v1.10:
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **options):
print('hello ', end='', file=self.stdout)
print('world', file=self.stdout)
Expected output: 预期产量:
hello world
Actual output: 实际产量:
hello
world
How do I correctly pass the ending character? 如何正确传递结束字符? I currently use a workaround of setting explicitly:
我目前使用明确设置的解决方法:
self.stdout.ending = ''
But this hack means you don't get all the features of the print function, you must use self.stdout.write
and prepare the bytes manually. 但是这个hack意味着你没有获得print函数的所有功能,你必须使用
self.stdout.write
并手动准备字节。
As is mentioned in Django 1.10's Custom Management Commands document: 正如Django 1.10的自定义管理命令文档中所述:
When you are using management commands and wish to provide console output, you should write to self.stdout and self.stderr , instead of printing to stdout and stderr directly.
当您使用管理命令并希望提供控制台输出时,您应该写入self.stdout和self.stderr ,而不是直接打印到stdout和stderr 。 By using these proxies, it becomes much easier to test your custom command.
通过使用这些代理,可以更轻松地测试自定义命令。 Note also that you don't need to end messages with a newline character, it will be added automatically, unless you specify the ending parameter :
另请注意,除非指定结束参数,否则不需要使用换行符结束消息,它将自动添加 。
self.stdout.write("Unterminated line", ending='')
Hence, in order to print in your Command
class, you should define your handle()
function as: 因此,为了在
Command
类中打印,您应该将handle()
函数定义为:
from django.core.management.base import BaseCommand
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout.write("hello ", ending='')
self.stdout.write("world", ending='')
# prints: hello world
Also, by explicitly setting self.stdout.ending = ''
, you are modifying the property of self.stdout
object. 此外,通过显式设置
self.stdout.ending = ''
,您正在修改self.stdout
对象的属性。 But you may not want this to be reflected in future calls of self.stdout.write()
. 但您可能不希望在将来的
self.stdout.write()
调用中反映出这一点。 Hence it will be better to use ending
parameter within self.stdout.write()
function (as demonstrated in sample code above). 因此,最好在
self.stdout.write()
函数中使用ending
参数(如上面的示例代码所示)。
As you mentioned "But this hack means you don't get all the features of the print function, you must use self.stdout.write and prepare the bytes manually." 正如您所提到的“但是这个hack意味着您没有获得打印功能的所有功能,您必须使用self.stdout.write并手动准备字节。” No, you do not have to worry about creating the
bytes
or other features of print()
, as self.stdout.write()
function belonging to OutputWrapper
class expects data to be in str
format. 不,您不必担心创建
print()
的bytes
或其他功能,因为属于OutputWrapper
类的self.stdout.write()
函数需要数据为str
格式。 Also I would like to mention that print()
and OutputWrapper.write()
behaves quite similar both acting as a wrapper around sys.stdout.write()
. 另外我想提一下,
print()
和OutputWrapper.write()
行为非常相似,都充当了sys.stdout.write()
的包装器。
The only difference between print()
and OutputWrapper.write()
is: print()
和OutputWrapper.write()
之间的唯一区别是:
print()
accepts message string as *args
with separator
parameter to join the the multiple strings, whereas print()
接受消息字符串为*args
with separator
参数以连接多个字符串,而 OutputWrapper.write()
accepts single message string OutputWrapper.write()
接受单个消息字符串 But this difference could be easily handled by explicitly joining the strings with separator and passing it to OutputWrapper.write()
. 但是,通过使用分隔符显式连接字符串并将其传递给
OutputWrapper.write()
可以轻松处理这种差异。
Conclusion: You do not have to worry about the additional features provided by print()
as there are none, and should go ahead with using self.stdout.write()
as suggested in this answer's quoted content from Custom Management Commands document. 结论:您不必担心
print()
提供的其他功能,因为没有,并且应该继续使用self.stdout.write()
如本回答引用的自定义管理命令文档中的内容所示。
If you are interested, you may check the source code of BaseCommand
and OutputWrapper
classes available at: Source code for django.core.management.base
. 如果您感兴趣,可以在以下位置检查
BaseCommand
和OutputWrapper
类的源代码 : django.core.management.base
源代码 。 It might help in clearing some of your doubts. 它可能有助于消除你的一些疑虑。 You may also check PEP-3105 related to Python 3's
print()
. 您也可以查看与Python 3的
print()
相关的PEP-3105 。
First of all, self.stdout
is an instance of django.core.management.base.OutputWrapper
command. 首先,
self.stdout
是django.core.management.base.OutputWrapper
命令的一个实例。 Its write
expects an str
, not bytes
, thus you can use 它的
write
期望str
,而不是bytes
,因此您可以使用
self.stdout.write('hello ', ending='')
self.stdout.write('world')
Actually self.stdout.write
does accept bytes but only whenever the ending
is an empty string - that's because its write
method is defined 实际上,
self.stdout.write
确实接受字节,但只有当ending
是空字符串时 - 这是因为它的write
方法是定义的
def write(self, msg, style_func=None, ending=None):
ending = self.ending if ending is None else ending
if ending and not msg.endswith(ending):
msg += ending
style_func = style_func or self.style_func
self._out.write(force_str(style_func(msg)))
If ending
is true, then msg.endswith(ending)
will fail if msg
is a bytes
instance and ending is a str
. 如果
ending
为true,那么msg.endswith(ending)
将失败,如果msg
是一个bytes
实例,结尾是str
。
Furthermore, print
with self.stdout
does work correctly when I set the self.stdout.ending = ''
explicitly; 此外,当我明确设置
self.stdout.ending = ''
时,使用self.stdout
print
确实可以正常工作; however doing this might mean that other code that uses self.stdout.write
expecting it to insert newlines, would fail. 但是这样做可能意味着使用
self.stdout.write
其他代码期望它插入换行符会失败。
In your case, what I'd do is to define a print
method for the Command
: 在你的情况下,我要做的是为
Command
定义一个print
方法:
from django.core.management.base import OutputWrapper
class PrintHelper:
def __init__(self, wrapped):
self.wrapped = wrapped
def write(self, s):
if isinstance(self.wrapped, OutputWrapper):
self.wrapped.write(s, ending='')
else:
self.wrapped.write(s)
class Command(BaseCommand):
def print(self, *args, file=None, **kwargs):
if file is None:
file = self.stdout
print(*args, file=PrintHelper(file), **kwargs)
def handle(self, *args, **options):
self.print('hello ', end='')
self.print('world')
You can make this into your own BaseCommand
subclass - and you can use it with different files too: 您可以将它变成您自己的
BaseCommand
子类 - 您也可以将它与不同的文件一起使用:
def handle(self, *args, **options):
for c in '|/-\\' * 100:
self.print('\rhello world: ' + c, end='', file=self.stderr)
time.sleep(0.1)
self.print('\bOK')
When setting self.stdout.ending
explicitly, the print command works as expected. 显式设置
self.stdout.ending
,print命令按预期工作。
The line ending needs to be set in self.stdout.ending
when file=self.stdout
, because that is an instance of django.core.management.base.OutputWrapper
. 当
file=self.stdout
,需要在self.stdout.ending
设置行结尾,因为这是django.core.management.base.OutputWrapper
一个实例。
class Command(BaseCommand):
def handle(self, *args, **options):
self.stdout.ending = ''
print('hello ', end='', file=self.stdout)
print('world', file=self.stdout)
Returns 返回
hello world
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.