This code generates "AttributeError: 'Popen' object has no attribute 'fileno'" when run with Python 2.5.1
当使用Python 2.5.1运行时,此代码生成“AttributeError:'Popen'对象没有属性'fileno'”
Code:
def get_blame(filename):
proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
proc.append(Popen(['tr', r"'\040'", r"';'"], stdin=proc[-1]), stdout=PIPE)
proc.append(Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=proc[-1]), stdout=PIPE)
return proc[-1].stdout.read()
Stack:
function walk_folder in blame.py at line 55
print_file(os.path.join(os.getcwd(), filename), path)
function print_file in blame.py at line 34
users = get_blame(filename)
function get_blame in blame.py at line 20
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
function __init__ in subprocess.py at line 533
(p2cread, p2cwrite,
function _get_handles in subprocess.py at line 830
p2cread = stdin.fileno()
This code should be working the python docs describe this usage.
这段代码应该是python docs描述这种用法。
5 个解决方案
#1
Three things
First, your ()'s are wrong.
首先,你的()错了。
Second, the result of subprocess.Popen()
is a process object, not a file.
其次,subprocess.Popen()的结果是一个进程对象,而不是一个文件。
proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
The value of proc[-1]
isn't the file, it's the process that contains the file.
proc [-1]的值不是文件,而是包含文件的进程。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
Third, don't do all that tr
and cut
junk in the shell, few things could be slower. Write the tr
and cut
processing in Python -- it's faster and simpler.
第三,不要在shell中完成所有tr和切割垃圾,很少有东西可能会变慢。在Python中编写tr和cut处理 - 它更快更简单。
#2
There's a few weird things in the script,
脚本中有一些奇怪的东西,
-
Why are you storing each process in a list? Wouldn't it be much more readable to simply use variables? Removing all the
.append()s
reveals an syntax error, several times you have passed stdout=PIPE to theappend
arguments, instead of Popen:为什么要将每个进程存储在列表中?简单地使用变量会不会更具可读性?删除所有.append()会显示语法错误,有几次你已经将stdout = PIPE传递给append参数,而不是Popen:
proc.append(Popen(...), stdout=PIPE)
So a straight-rewrite (still with errors I'll mention in a second) would become..
因此,直接重写(仍然会在一秒钟内提到错误)将成为......
def get_blame(filename): blame = Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE) tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame, stdout=PIPE) tr2 = Popen(['tr', r"'\040'", r"';'"], stdin=tr1), stdout=PIPE) cut = Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=tr2, stdout=PIPE) return cut.stdout.read()
-
On each subsequent command, you have passed the Popen object, not that processes
stdout
. From the "Replacing shell pipeline" section of the subprocess docs, you do..在每个后续命令中,您已经传递了Popen对象,而不是处理stdout。从子流程文档的“替换shell管道”部分,您可以...
p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
..whereas you were doing the equivalent of
stdin=p1
...你做的相当于stdin = p1。
The
tr1 =
(in the above rewritten code) line would become..tr1 =(在上面的重写代码中)行将成为..
tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE)
-
You do not need to escape commands/arguments with subprocess, as subprocess does not run the command in any shell (unless you specify
shell=True
). See the Securitysection of the subprocess docs.您不需要使用子进程转义命令/参数,因为子进程不在任何shell中运行该命令(除非您指定shell = True)。请参阅子流程文档的安全性部分。
Instead of..
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
..you can safely do..
..你可以安全地做..
Popen(['svn', 'blame', filename], stdout=PIPE)
-
As S.Lott suggested, don't use subprocess to do text-manipulations easier done in Python (the tr/cut commands). For one, tr/cut etc aren't hugely portable (different versions have different arguments), also they are quite hard to read (I've no idea what the tr's and cut are doing)
正如S.Lott建议的那样,不要使用子进程在Python中更容易地完成文本操作(tr / cut命令)。对于一个,tr / cut等不是非常便携(不同的版本有不同的参数),它们也很难读(我不知道tr和cut正在做什么)
If I were to rewrite the command, I would probably do something like..
如果我要重写命令,我可能会做类似的事情......
def get_blame(filename): blame = Popen(['svn', 'blame', filename], stdout=PIPE) output = blame.communicate()[0] # preferred to blame.stdout.read() # process commands output: ret = [] for line in output.split("\n"): split_line = line.strip().split(" ") if len(split_line) > 2: rev = split_line[0] author = split_line[1] line = " ".join(split_line[2:]) ret.append({'rev':rev, 'author':author, 'line':line}) return ret
#3
You want the stdout of the process, so replace your stdin=proc[-1]
with stdin=proc[-1].stdout
你想要进程的stdout,所以用stdin = proc [-1]替换你的stdin = proc [-1] .stdout
Also, you need to move your paren, it should come after the stdout
argument.
此外,你需要移动你的paren,它应该在stdout参数之后。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
should be:
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
Fix your other append
calls in the same way.
以相同的方式修复您的其他追加调用。
#4
looks like syntax error. except first append the rest are erroneous (review brackets).
看起来像语法错误。除了第一次追加其余的都是错误的(审查括号)。
#5
Like S.Lott said, processing the text in Python is better.
就像S.Lott所说,用Python处理文本更好。
But if you want to use the cmdline utilities, you can keep it readable by using shell=True
:
但是如果要使用cmdline实用程序,可以使用shell = True使其可读:
cmdline = r"svn blame %s | tr -s '\040' | tr '\040' ';' | cut -d \; -f 3" % shellquote(filename)
return Popen(cmdline, shell=True, stdout=PIPE).communicate()[0]
#1
Three things
First, your ()'s are wrong.
首先,你的()错了。
Second, the result of subprocess.Popen()
is a process object, not a file.
其次,subprocess.Popen()的结果是一个进程对象,而不是一个文件。
proc = []
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
The value of proc[-1]
isn't the file, it's the process that contains the file.
proc [-1]的值不是文件,而是包含文件的进程。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
Third, don't do all that tr
and cut
junk in the shell, few things could be slower. Write the tr
and cut
processing in Python -- it's faster and simpler.
第三,不要在shell中完成所有tr和切割垃圾,很少有东西可能会变慢。在Python中编写tr和cut处理 - 它更快更简单。
#2
There's a few weird things in the script,
脚本中有一些奇怪的东西,
-
Why are you storing each process in a list? Wouldn't it be much more readable to simply use variables? Removing all the
.append()s
reveals an syntax error, several times you have passed stdout=PIPE to theappend
arguments, instead of Popen:为什么要将每个进程存储在列表中?简单地使用变量会不会更具可读性?删除所有.append()会显示语法错误,有几次你已经将stdout = PIPE传递给append参数,而不是Popen:
proc.append(Popen(...), stdout=PIPE)
So a straight-rewrite (still with errors I'll mention in a second) would become..
因此,直接重写(仍然会在一秒钟内提到错误)将成为......
def get_blame(filename): blame = Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE) tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame, stdout=PIPE) tr2 = Popen(['tr', r"'\040'", r"';'"], stdin=tr1), stdout=PIPE) cut = Popen(['cut', r"-d", r"\;", '-f', '3'], stdin=tr2, stdout=PIPE) return cut.stdout.read()
-
On each subsequent command, you have passed the Popen object, not that processes
stdout
. From the "Replacing shell pipeline" section of the subprocess docs, you do..在每个后续命令中,您已经传递了Popen对象,而不是处理stdout。从子流程文档的“替换shell管道”部分,您可以...
p1 = Popen(["dmesg"], stdout=PIPE) p2 = Popen(["grep", "hda"], stdin=p1.stdout, stdout=PIPE)
..whereas you were doing the equivalent of
stdin=p1
...你做的相当于stdin = p1。
The
tr1 =
(in the above rewritten code) line would become..tr1 =(在上面的重写代码中)行将成为..
tr1 = Popen(['tr', '-s', r"'\040'"], stdin=blame.stdout, stdout=PIPE)
-
You do not need to escape commands/arguments with subprocess, as subprocess does not run the command in any shell (unless you specify
shell=True
). See the Securitysection of the subprocess docs.您不需要使用子进程转义命令/参数,因为子进程不在任何shell中运行该命令(除非您指定shell = True)。请参阅子流程文档的安全性部分。
Instead of..
proc.append(Popen(['svn', 'blame', shellquote(filename)], stdout=PIPE))
..you can safely do..
..你可以安全地做..
Popen(['svn', 'blame', filename], stdout=PIPE)
-
As S.Lott suggested, don't use subprocess to do text-manipulations easier done in Python (the tr/cut commands). For one, tr/cut etc aren't hugely portable (different versions have different arguments), also they are quite hard to read (I've no idea what the tr's and cut are doing)
正如S.Lott建议的那样,不要使用子进程在Python中更容易地完成文本操作(tr / cut命令)。对于一个,tr / cut等不是非常便携(不同的版本有不同的参数),它们也很难读(我不知道tr和cut正在做什么)
If I were to rewrite the command, I would probably do something like..
如果我要重写命令,我可能会做类似的事情......
def get_blame(filename): blame = Popen(['svn', 'blame', filename], stdout=PIPE) output = blame.communicate()[0] # preferred to blame.stdout.read() # process commands output: ret = [] for line in output.split("\n"): split_line = line.strip().split(" ") if len(split_line) > 2: rev = split_line[0] author = split_line[1] line = " ".join(split_line[2:]) ret.append({'rev':rev, 'author':author, 'line':line}) return ret
#3
You want the stdout of the process, so replace your stdin=proc[-1]
with stdin=proc[-1].stdout
你想要进程的stdout,所以用stdin = proc [-1]替换你的stdin = proc [-1] .stdout
Also, you need to move your paren, it should come after the stdout
argument.
此外,你需要移动你的paren,它应该在stdout参数之后。
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1]), stdout=PIPE)
should be:
proc.append(Popen(['tr', '-s', r"'\040'"], stdin=proc[-1].stdout, stdout=PIPE))
Fix your other append
calls in the same way.
以相同的方式修复您的其他追加调用。
#4
looks like syntax error. except first append the rest are erroneous (review brackets).
看起来像语法错误。除了第一次追加其余的都是错误的(审查括号)。
#5
Like S.Lott said, processing the text in Python is better.
就像S.Lott所说,用Python处理文本更好。
But if you want to use the cmdline utilities, you can keep it readable by using shell=True
:
但是如果要使用cmdline实用程序,可以使用shell = True使其可读:
cmdline = r"svn blame %s | tr -s '\040' | tr '\040' ';' | cut -d \; -f 3" % shellquote(filename)
return Popen(cmdline, shell=True, stdout=PIPE).communicate()[0]