从Python访问errno?

时间:2009-03-19 04:00:34

标签: python linux python-2.5 errno

我遇到了一个相当复杂的Python模块,它不会返回有用的错误代码(它实际上是无法安静地失败)。但是,它调用的底层C库设置了errno。

正常情况下,errno会超过OSError属性,但由于我没有异常,我无法理解它。

使用ctypes,libc.errno不起作用,因为errno是GNU libc中的一个宏。 Python 2.6有一些功能,但Debian仍然使用Python 2.5。将C模块插入我的纯Python程序只是为了阅读errno令我感到厌恶。

有没有办法访问errno?只有Linux的解决方案很好,因为被包装的库是仅限Linux的。我也不必担心线程,因为我只是在这可能失败的时候运行一个线程。

6 个答案:

答案 0 :(得分:17)

以下是一段允许访问errno的代码:

from ctypes import *

libc = CDLL("libc.so.6")

get_errno_loc = libc.__errno_location
get_errno_loc.restype = POINTER(c_int)

def errcheck(ret, func, args):
    if ret == -1:
        e = get_errno_loc()[0]
        raise OSError(e)
    return ret

copen = libc.open
copen.errcheck = errcheck

print copen("nosuchfile", 0)

重要的是你在函数调用后尽快检查errno,否则它可能已被覆盖。

答案 1 :(得分:14)

更新:在 Python 2.6 + 上,使用ctypes.get_errno()

Python 2.5

下面的代码不可靠(或者全面,有许多方法errno可以定义),但它应该让你开始(或重新考虑你在一个小扩展模块上的位置(毕竟在Debian上{{} 1}}或python setup.py install应该没有问题来构建它))。来自http://codespeak.net/pypy/dist/pypy/rpython/lltypesystem/ll2ctypes.py

easy_install

if not hasattr(ctypes, 'get_errno'): # Python 2.5 or older if sys.platform == 'win32': standard_c_lib._errno.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib._errno() elif sys.platform in ('linux2', 'freebsd6'): standard_c_lib.__errno_location.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__errno_location() elif sys.platform in ('darwin', 'freebsd7'): standard_c_lib.__error.restype = ctypes.POINTER(ctypes.c_int) def _where_is_errno(): return standard_c_lib.__error() ctypes.get_errno = lambda: _where_is_errno().contents.value

standard_c_lib

答案 2 :(得分:9)

您似乎可以使用此修补程序为您提供ctypes.get_errno/set_errno

http://bugs.python.org/issue1798

这是实际应用于存储库的补丁:

http://svn.python.org/view?view=rev&revision=63977

否则,添加一个新的C模块除了返回errno /之外什么都不做/是/恶心,但是你正在使用的库也是如此。我会这样做,而不是自己修补python。

答案 3 :(得分:9)

放弃并跟踪C标题。

import ctypes
c = ctypes.CDLL("libc.so.6")
c.__errno_location.restype = ctypes.POINTER(ctypes.c_int)
c.write(5000, "foo", 4)
print c.__errno_location().contents # -> c_long(9)

它在python命令提示符下不起作用,因为它重置errno以从stdin读取。

一旦你知道magic word of __errno_location,这就像一个普通的模式。但只有errno我很遗憾。

答案 4 :(得分:1)

我不确定这是你和Jerub所指的那个,但是你可以编写一个非常短的C扩展名,只输出errno,即the python language interface

否则,我同意你的意见,不得不添加这一小段编译代码是一件痛苦的事。

答案 5 :(得分:0)

ctypes实际上提供了一种访问python的c实现的标准方法,即使用errno。我没有在我的(linux)系统上测试过这个,但这应该是非常便携的:

ctypes.c_int.in_dll(ctypes.pythonapi, “错误号”)

返回包含当前值的c_int。