Python 2.6:os.rename()或os.renames()报告OSError但文件名为None

3
如果您调用os.rename提供的文件或目录不存在,则引发的OSError将通过将其设置为None来省略文件名。这是2.6中存在的错误吗?是否已在某些较新版本中解决?
您可以通过简单地执行以下操作来重现此问题:
python -c 'import os ; os.rename("/tmp/abc", "/tmp/cba")'

当既不存在/tmp/abc,也不存在/tmp/cba时。

我在思考是否应该实现一个包装器来拦截OSError并在重新发送错误之前更正文件名属性。

更新

我实现了一个简单的测试包装器,它产生了期望的行为:

$ /tmp/osrename.py
Traceback (most recent call last):
File "/tmp/osrename.py", line 26, in <module>
  os.rename('/tmp/abc', '/tmp/cba')
File "/tmp/osrename.py", line 8, in __os_rename
  os_rename(a, b)
OSError: [Errno 2] No such file or directory: '/tmp/abc'

这是实现代码:

import os, sys

def __os_rename_wrapper(os_rename):
    def __os_rename(a, b):
        try:
            os_rename(a, b)

        except OSError:
            exc = sys.exc_info()[1]

            if getattr(exc, 'filename', None) is None:
                exc.filename = "{0} -> {1}".format(repr(a), repr(b))

            raise

    __os_rename.__name__ = os_rename.__name__
    __os_rename.__doc__ = os_rename.__doc__

    return __os_rename

os.rename = __os_rename_wrapper(os.rename)


os.rename('/tmp/abc', '/tmp/cba')

有没有一种方法可以钩住模块加载,以便可以动态地应用这些修复呢?

我在3.4.3中得到了以下错误信息:FileNotFoundError: [Errno 2] No such file or directory: '/tmp/abc' -> '/tmp/cba'。该错误本身还显示了正确的filenamefilename2属性。所以看起来已经修复了? - user2124834
https://www.python.org/dev/peps/pep-0302/ - Craig
1
重命名函数不知道是哪个文件名导致了失败,这就是为什么在Python3中正确的修复方法包括添加第二个文件名属性。 - Random832
正确。但是有些东西比“无”要好。我可以使异常处理程序更加复杂,并在 / b 上执行 os.exists,其中 errno 是 ENOEXIST - Craig
请提供需要翻译的英文内容。 - Craig
1个回答

1
在Python 2.7.8中也会发生相同的情况,因此我认为这是有意的。
但是:
在Python 3.4中,如@Random832所述,向OSError添加了第二个属性filename2,并且正确设置了属性。
这个PEP 3151可以提供一些信息,特别是:
由于WindowsError被合并到OSError中,后者在Windows下获得了一个winerror属性。在不相关的情况下,它被设置为None,就像errno、filename和strerror属性一样(例如当Python代码直接引发OSError时)。
以下是:
为了保持有用的兼容性,这些子类仍然应该为超类定义的各种异常属性设置适当的值(例如errno、filename和可选的winerror)。
PEP已被标记为3.3版本的接受。此外,3.3文档说:
对于涉及文件系统路径的异常(例如open()或os.unlink()),异常实例将包含一个附加属性filename,该属性是传递给函数的文件名。
并不清楚为哪些函数设置了该属性,但基于上述内容,我认为rename函数肯定涉及文件名,因此应该设置filename属性。
如果您发现任何其他PEP相关内容,请随时添加。
目前我能想到的唯一原因是,在rename函数中使用了两个文件名,因此可能不清楚要在异常filename属性上设置哪一个(对此有什么想法吗?)。
如果需要设置值,则您关于更正属性的解决方案是可行的,至少在我看来。

我更新了我的示例,以提供重命名中的3.3.0行为,同时指定文件ab。这主要是为了记录日志,以便在尝试诊断中止原因时使用。 - Craig
我发布后看到了这条信息,我之前不知道有第二个filename2属性,因为我在文档中没有看到。实际上,wrapper的解决方案很好,至于hook,我不知道是否有类似的东西,但你可以像django一样使用本地six模块来修补os以实现可移植性。 - qwattash
1
我确实这样做了。我创建了一个 python_fixes/os/init.py 模块,我在我的应用程序中明确加载它。然后,它将包装器方法应用于 os 模块。我编写的单元测试现在似乎正常工作。 - Craig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接