Frage

Ich bin mit einem ziemlich komplexen Python-Modul stecken, die nicht nützlich Fehlercodes zurückgibt (es verstörend still tatsächlich ausfällt). Es ist jedoch die zugrunde liegenden C-Library setzt errno.

Normalerweise errno kommt über OSError Attribute, aber da ich keine Ausnahme, ich kann es nicht erreichen.

ctypes verwenden, libc.errno funktioniert nicht, weil errno ein Makro in GNU libc ist. Python 2.6 hat einige affordances aber Debian verwendet noch Python 2.5. nur einen C-Modul in mein reinen Python-Programm einfügen mich lesen errno ekelt.

Gibt es eine Möglichkeit errno zugreifen? Eine Linux-only Lösung ist in Ordnung, da die Bibliothek eingewickelt ist Linux-only. Ich auch muß nicht über Themen kümmern, da ich nur einen Thread während der Zeit ausgeführt wird, in dem dies nicht gelingen kann.

War es hilfreich?

Lösung

Update: Ein Python 2.6 + , verwenden Sie 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 

Wo 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())

Andere Tipps

Hier ist ein Ausschnitt von Code, der errno zugreifen kann:

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)

Das Wichtigste ist, dass Sie errno so bald wie möglich nach dem Funktionsaufruf überprüfen, sonst ist es bereits überschrieben werden kann.

Es sieht aus wie Sie diesen Patch verwenden können, die Sie mit ctypes.get_errno/set_errno liefert

http://bugs.python.org/issue1798

Dies ist der Patch, der auf das Repository tatsächlich angewandt wurde:

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

Ansonsten eine neue C-Modul hinzufügen, die nichts anderes als Rückkehr errno tut / ist / ekelhaft, aber so ist die Bibliothek, die Sie verwenden. Das würde ich mich in Vorliebe tut Python Patchen.

gab auf und verfolgt durch die C-Header.

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)

Es funktioniert nicht in der Python-Eingabeaufforderung, weil es errno setzt von stdin zu lesen.

Wenn Sie die Zauberwort von __errno_location wissen dies sieht aus wie ein gemeinsames Muster . Aber mit nur errno Ich war ziemlich verloren.

Ich bin mir nicht sicher, ob dies ist, was Sie und Jerub beziehen sich auf, aber man konnte eine sehr kurze C-Erweiterung schreiben, die nur errno, dh mit die Schnittstelle Sprache python.

Ansonsten stimme ich Ihnen zu, dass dieses klein bisschen kompilierte Code hinzufügen zu müssen ist ein Schmerz.

ctypes gibt tatsächlich einen Standard Python c Implementierung zuzugreifen, die errno verwendet. Ich habe das andere auf etwas nicht getestet als meine (Linux-System), aber dies sollte sehr tragbar:

ctypes.c_int.in_dll (ctypes.pythonapi "errno")

, die gibt einen C_INT den aktuellen Wert enthält.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top