当前位置:  开发笔记 > 编程语言 > 正文

从Python访问errno?

如何解决《从Python访问errno?》经验,为你挑选了4个好方法。

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

通常errno来自OSError属性,但由于我没有异常,我无法得到它.

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

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



1> theller..:

以下是允许访问的代码片段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在函数调用后尽快检查,否则它可能已被覆盖.



2> jfs..:

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

Python 2.5

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

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:

def get_libc_name():
    if sys.platform == 'win32':
        # Parses sys.version and deduces the version of the compiler
        import distutils.msvccompiler
        version = distutils.msvccompiler.get_build_version()
        if version is None:
            # This logic works with official builds of Python.
            if sys.version_info < (2, 4):
                clibname = 'msvcrt'
            else:
                clibname = 'msvcr71'
        else:
            if version <= 6:
                clibname = 'msvcrt'
            else:
                clibname = 'msvcr%d' % (version * 10)

        # If python was built with in debug mode
        import imp
        if imp.get_suffixes()[0][0] == '_d.pyd':
            clibname += 'd'

        return clibname+'.dll'
    else:
        return ctypes.util.find_library('c')

# Make sure the name is determined during import, not at runtime
libc_name = get_libc_name() 
standard_c_lib = ctypes.cdll.LoadLibrary(get_libc_name())



3> Jerub..:

看起来你可以使用这个为你提供的补丁 ctypes.get_errno/set_errno

http://bugs.python.org/issue1798

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

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

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



4> 小智..:

放弃并通过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读取.

一旦你知道__errno_location的神奇词汇,这就像一个普通的模式.但是,只有错误,我很丢失.

推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有