c_int - ¿Acceso a errno desde Python?
ctypes python 3 (6)
Actualización: en Python 2.6+ , use ctypes.get_errno()
.
Python 2.5
El código de advertencia no es confiable (o completo, hay una gran cantidad de maneras en que se podría definir errno
) pero debería comenzar (o reconsiderar su posición en un pequeño módulo de extensión (después de todo en python setup.py install
o easy_install
debería tener) no hay problema para construirlo)). De 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
Donde 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())
Estoy atascado con un módulo Python bastante complejo que no devuelve códigos de error útiles (en realidad falla de manera silenciosa). Sin embargo, la biblioteca C subyacente a la que llama sets errno.
Normalmente, el error aparece en los atributos OSError, pero como no tengo una excepción, no puedo hacerlo.
Al usar ctypes, libc.errno no funciona porque errno es una macro en GNU libc. Python 2.6 tiene algunas posibilidades, pero Debian todavía usa Python 2.5. Insertar un módulo C en mi programa Python puro solo para leer errno me disgusta.
¿Hay alguna manera de acceder a errno? Una solución solo para Linux está bien, ya que la biblioteca que está siendo envuelta es solo para Linux. Tampoco tengo que preocuparme por los hilos, ya que solo estoy ejecutando un hilo durante el tiempo en que esto puede fallar.
Aquí hay un fragmento de código que permite acceder a 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)
Lo importante es que compruebe errno
tan pronto como sea posible después de su llamada a la función, de lo contrario, es posible que ya se haya sobrescrito.
No estoy seguro de a qué se refiere usted y Jerub, pero podría escribir una extensión C muy corta que solo exporte errno, es decir, con la interfaz de lenguaje Python .
De lo contrario, estoy de acuerdo contigo en que tener que agregar este pequeño fragmento de código compilado es un dolor.
Parece que puedes usar este parche que te proporcionará ctypes.get_errno/set_errno
http://bugs.python.org/issue1798
Este es el parche que realmente se aplicó al repositorio:
http://svn.python.org/view?view=rev&revision=63977
De lo contrario, agregar un nuevo módulo C que no haga nada más que devolver errno / is / disgusting, pero también lo es la biblioteca que está usando. Lo haría con preferencia a parchear python a mí mismo.
Renunció y rastreado a través de los encabezados en 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)
No funciona en el símbolo del sistema de python porque restablece errno para leer desde stdin.
Una vez que conozca la palabra mágica de __errno_location, este parece un patrón común. Pero con solo errno estaba bastante perdido.
ctypes en realidad ofrece una forma estándar de acceder a la implementación de c de python, que está usando errno. No he probado esto en otra cosa que no sea mi sistema (linux), pero debería ser muy portátil:
ctypes.c_int.in_dll (ctypes.pythonapi, "errno")
que devuelve un c_int que contiene el valor actual.