Python 2.6.4 marshal.load不接受使用subprocess.Popen创建的打开文件对象

时间:2010-07-14 19:40:31

标签: python

这是一个非常不幸的情况。 Maya 2011附带2.6.4,此代码不起作用:

pipe = subprocess.Popen( 'p4 -G edit C:/somefile.txt', stdout=subprocess.PIPE).stdout

try:
    while 1:
        record = marshal.load( pipe )
        list.append( record )
except EOFError:
    pass

各种2.5版本的工作和最新的2.6.5也可以使用,当然不是Maya附带的版本!它抛出了这个错误:

# Error: TypeError: file <maya console> line 3: marshal.load() arg must be file #

最佳行动方案是什么?

为了继续生活,代码被更改为只是转储文件,因此marshal.load可以加载实际文件。虽然这很有效,但它很蹩脚。

Maya 2011通过zip访问python所以,作为一个小测试,我压缩了2.6.5的Python26 / Lib并将指向2.6.4 zip的sys.path条目换成2.6.5 zip。虽然我没有对此进行过广泛的测试,但这似乎有效。我无法分辨这是否比上述更好或更差。

理想情况下(我认为)2.6.4中有一些东西可以做到这一点,无需混合python版本或始终将tempfiles写入磁盘。有什么想法吗?

有关marshal.loads()的更新

尝试使用marshal.loads(),它的工作原理是它没有错误,但它仍然无法正常工作。我肯定在黑暗中摸索着这些东西。如果文件操作是单独完成的,那么perforce的东西是无法忍受的慢,在一个查询中执行它们是必须的。原始代码执行了此操作:

files = [a,b,c...n] # Huge list of files
p = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
(fi, pipe) = (p.stdin, p.stdout)

# Fill the command up with all the files
for file in files:
    fi.write(file + '\n')
fi.close()

# Get all the results
try:
    while 1:
        record = marshal.load( pipe )
        listData.append( record )
except EOFError:
    pass

我不知道为什么会这样(在2.5.x / 2.6.5中),但确实如此; listData最终作为所有文件结果的列表。我无法弄清楚如何使用marshal.loads(),我只回到第一个结果。这个方法几乎逐字逐句地从perforce开始,所以我知道这是应该做的事情。很容易想象我只是不知道如何正确使用子进程和编组。

更新2 marshal.loads()完全可以正常工作!

经过更多测试后,pipe.read()提供了所有数据,但它包含一些空字符或其他我不完全理解的内容,因此marshal.loads()只会读取第一个条目。在这种特殊情况下,我可以将数据拆分为“{”并收集数据。

listData = []
results = pipe.read().split("{")
# Skip the first entry since it's empty
for result in results[1:]:
    listData.append( marshal.loads( "{" + result) )

感谢Cristian指出我正确的方向,并希望任何使用perforce升级到Maya 2011的人都会让事情变得更顺畅。

3 个答案:

答案 0 :(得分:3)

这是一个老问题,但我想我会添加我为其他人遇到的问题。

不幸的是,senyacap的答案似乎不适用于Windows,marshal.load(tempf)无法说明临时文件不是文件对象。传入tempf.file也无效。

所以,另一个(可怕的)解决方法(这是专门用于处理Perforce,因为没有其他选项可以使用marshal模块),是这样的:

p = subprocess.Popen ( cmd, stdout = subprocess.PIPE ) 
( stdoutdata, stderrdata ) = p.communicate ( )

unmarshalled = []
while stdoutdata:
    record = marshal.loads ( stdoutdata )
    unmarshalled.append ( record )
    remarshalled = marshal.dumps ( record )
    stdoutdata = stdoutdata [ len ( remarshalled ) : ]

答案 1 :(得分:2)

使用-G选项解组p4的输出时遇到同样的问题。 marshal.loads(str)仅读取第一条记录,marshal.load(StringIO(str))以'marshal.load()arg必须为文件'失败。 而不是拆分建议我使用临时文件解决方法:

import subprocess, marshal, tempfile

tempf = tempfile.TemporaryFile()
subprocess.Popen(cmd, stdout=tempf).communicate()
tempf.seek(0)
try:
    while 1:
        record = marshal.load(tempf)
        listData.append( record )
except EOFError:
    pass
tempf.close()

请注意,python会在您关闭它时立即删除临时文件。

答案 2 :(得分:1)

最后我去了。

import shutil
import os
import tempfile

def decode_list(outputstr):
  tmpfolder = tempfile.mkdtemp()
  try:
      binname = os.path.join(tmpfolder, "p4_decode.bin")
      with open(binname, "wb") as binfile:
          binfile.write(outputstr)

      with open(binname, "rb") as binfile:
          ret = []
          while True:
              try:
                  item = marshal.load(binfile)
                  ret.append(item)
              except EOFError:
                  return ret
  finally:
      if tmpfolder and os.path.isdir(tmpfolder):
          shutil.rmtree(tmpfolder)