一尘不染

从Python访问errno?

linux

我被困在一个相当复杂的Python模块中,该模块不会返回有用的错误代码(它实际上会无声地失败而失败)。但是,它调用的基础C库设置了errno。

通常,errno是通过OSError属性传入的,但是由于我没有异常,因此无法理解。

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

有什么办法可以访问errno?仅Linux的解决方案很好,因为要包装的库仅Linux。我也不必担心线程,因为我只会在可能失败的时间内运行一个线程。


阅读 315

收藏
2020-06-07

共1个答案

一尘不染

更新:在 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())
2020-06-07