简体   繁体   English

NamedTemporaryFile 存在,但外部程序无法访问它

[英]NamedTemporaryFile exists, but external program can't access it

This is a follow-up of sorts to this question about using NamedTemporaryFile()这是关于使用NamedTemporaryFile() 这个问题的后续

I have a function that creates and writes to a temporary file.我有一个创建和写入临时文件的函数。 I then want to use that file in a different function, which calls a terminal command that uses that file (the program is from the Blast+ suite, blastn ).然后我想在不同的函数中使用该文件,该函数调用使用该文件的终端命令(该程序来自 Blast+ 套件, blastn )。

def db_cds_to_fna(collection="genes"):  # collection gets data from mongoDB

    tmp_file = NamedTemporaryFile()
    # write stuff to file

    return tmp_file

def blast_all(blast_db, collection="genes"):        

    tmp_results = NamedTemporaryFile()    
    db_fna = db_cds_to_fna(collection) # should return another file object

    Popen(
        ['blastn',
         '-query', db_fna.name,
         '-db', blast_db,
         '-out', tmp_results.name,
         '-outfmt', '5']  # xml output
    )

    return tmp_results

When I call blast_all , I get an error from the blastn command:当我调用blast_all ,我从blastn命令收到一个错误:

Command line argument error: Argument "query". File is not accessible:  `/var/folders/mv/w3flyjvn7vnbllysvzrf9y480000gn/T/tmpAJVWoz'

But, just prior to the Popen call, if I do os.path.isfile(db_fna.name) it evaluates to True .但是,刚刚前Popen电话,如果我做os.path.isfile(db_fna.name)评估为True I can also do我也可以

print Popen(['head', db_fna.name]).communicate(0)

And it properly spits out the first lines of the file.它正确地吐出文件的第一行。 So the file exists, and it's readable.所以该文件存在,并且是可读的。 Further, I use the same strategy to call a different program from the same blast+ suite ( makeblastdb , see question linked at the top) and it works.此外,我使用相同的策略从同一个blast+ 套件( makeblastdb ,请参阅顶部链接的问题)调用不同的程序并且它有效。 Is there possibly some problem with permissions?权限可能有问题吗? FWIW blastn returns the same error if the file doesn't exist, but it seems clear that I'm correctly creating the file and it's readable when I make the Popen call, so I'm stumped.如果文件不存在, blastn返回相同的错误,但很明显我正确地创建了文件并且在我进行Popen调用时它是可读的,所以我很难过。

I've had a very similar problem at some point.我在某些时候遇到了非常相似的问题。 I was searching for ages, thinking I was never going to find the cause.我找了很久,以为我永远也找不到原因。

In my case, the issue was due to file-system latency.就我而言,问题是由于文件系统延迟造成的。 I think I ended up putting a dirty hack in place using time.sleep to give the file system some time to create the temp file before starting to access it in the subproces.我想我最终使用time.sleep进行了一次肮脏的黑客攻击,以便在开始在子过程中访问临时文件之前给文件系统一些时间来创建临时文件。

Hope that helps!希望有帮助!

I believe I figured out the things conspiring to cause this behavior.我相信我弄清楚了导致这种行为的阴谋。 First, the Popen() function does not normally wait until the external command finishes before proceeding past it.首先, Popen()函数通常不会等到外部命令完成后再继续执行。 Second, because as user glibdud mentioned in his answer to my other question, NamedTemporaryFile acts like TemporaryFile in that其次,因为正如用户 glibdud在他对我的另一个问题的回答中提到的那样NamedTemporaryFile作用类似于TemporaryFile

It will be destroyed as soon as it is closed (including an implicit close when the object is garbage collected).它会在关闭后立即销毁(包括对象被垃圾回收时的隐式关闭)。

Since the end of my blast_all() function does not return the query temp file, it gets closed and garbage collected while the external blastn command is running, so the file is deleted.由于我的blast_all()函数的结尾没有返回query临时文件,它在外部blastn命令运行时被关闭并被垃圾收集,因此该文件被删除。 I'm guessing that the external head command goes so quickly it doesn't encounter this problem, but blastn can take up to a couple of minutes to run.我猜想外部head命令运行得如此之快,它不会遇到这个问题,但blastn可能需要长达几分钟的时间才能运行。

So the solution is to force Popen() to wait:所以解决方案是强制Popen()等待:

Popen(
    ['blastn',
     '-query', db_fna.name,
     '-db', blast_db,
     '-out', tmp_results.name,
     '-outfmt', '5']  # xml output
).wait()

I think the problem may be that the OS has not synced the file to disk.我认为问题可能是操作系统没有将文件同步到磁盘。 After you write to the file descriptor do:写入文件描述符后,请执行以下操作:

tmp_file.flush()
os.fsync(tmp_file)

https://docs.python.org/3/library/os.html#os.fsync https://docs.python.org/3/library/os.html#os.fsync

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM