Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
从Python访问errno?_Python_Linux_Python 2.5_Errno - Fatal编程技术网

从Python访问errno?

从Python访问errno?,python,linux,python-2.5,errno,Python,Linux,Python 2.5,Errno,我遇到了一个相当复杂的Python模块,该模块不返回有用的错误代码(它实际上以令人不安的方式失败)。但是,它调用的底层C库设置errno 通常情况下,errno会超过OSError属性,但因为我没有异常,所以我无法处理它 使用ctypes,libc.errno不起作用,因为errno是GNULIBC中的宏。Python2.6有一些启示,但Debian仍然使用Python2.5。在纯Python程序中插入C模块只是为了读取errno,这让我很反感 有没有办法访问errno?只使用Linux的解决方

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

通常情况下,errno会超过OSError属性,但因为我没有异常,所以我无法处理它

使用ctypes,libc.errno不起作用,因为errno是GNULIBC中的宏。Python2.6有一些启示,但Debian仍然使用Python2.5。在纯Python程序中插入C模块只是为了读取errno,这让我很反感


有没有办法访问errno?只使用Linux的解决方案是可以的,因为要包装的库是只使用Linux的。我也不必担心线程,因为在这可能失败的时间内,我只运行一个线程。

看起来您可以使用此修补程序为您提供
ctypes。get\u errno/set\u errno

这是实际应用于存储库的修补程序:


否则,添加一个新的C模块,它只返回errno/is/厌恶,但您正在使用的库也是如此。我宁愿这样做,也不愿自己修补python。

我不确定这是否是您和Jerub所指的,但您可以编写一个非常短的C扩展,只导出errno,即使用


否则,我同意您的观点,必须添加这一小段编译代码是一件痛苦的事情。

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


一旦你知道了答案,这看起来就像是一个常见的模式。但是,仅仅使用它我就迷路了。

更新:在Python 2.6+上,使用

Python 2.5 下面的代码不可靠(或者说不全面,有很多方法可以定义
errno
),但它应该可以让您开始(或者重新考虑您在一个小型扩展模块上的位置(毕竟在Debian
python setup.py安装
easy_install
上构建它应该没有问题)。从

其中
标准库

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())
def get_libc_name():
如果sys.platform==“win32”:
#解析sys.version并推断编译器的版本
导入distutils.msvccompiler
version=distutils.msvccompiler.get\u build\u version()
如果版本为“无”:
#这种逻辑适用于Python的官方版本。
如果系统版本信息<(2,4):
clibname='msvcrt'
其他:
clibname='msvcr71'
其他:

如果版本这里有一段代码,允许访问
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
,否则它可能已经被覆盖。

ctypes实际上提供了一种访问python的c实现的标准方法,即使用errno。除了我的(linux)系统之外,我还没有在任何其他系统上测试过这一点,但这应该是非常可移植的:

ctypes.c_int.in_dll(ctypes.pythonapi,“errno”)


它返回一个包含当前值的c_int。

这是一个不错的最后手段,但要求模块用户修补自己的Python副本有点苛刻。我希望有人知道一个神奇的咒语,让2.5的ctypes达到errno,即使它不是100%洁食。errcheck界面很酷,谢谢你指出。不幸的是,J.F.塞巴斯蒂安(J.F.Sebastian)也因为告诉我如何在BSD上这样做而获胜。+1:因为他明确指出,
errno
可能会在你阅读之前被更改;为了实现通过
errcheck
来阻止它,下面将正确设置OSError异常上的errno和strerror属性:raise OSError(e,errno.errorcode[e])我发现以下内容对于检查返回值是否为-1或NULL非常有用:
如果不是ret或ctypes.cast(ret,ctypes.POINTER(ctypes.c_int))==-1:
事实上,现在适当的方法是使用ctypes.get_errno()。啊,这对我很有帮助。在浏览CTypesAPI时,我从来没有看到过这一点。如果您的目标是2.6或更高版本,
ctypes.get\u 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)