Python から errno にアクセスしますか?
-
20-08-2019 - |
質問
私は、有用なエラー コードを返さない、かなり複雑な Python モジュールで行き詰まっています (実際には、不穏な音もなく失敗します)。ただし、呼び出す基礎となる C ライブラリは errno を設定します。
通常、errno は OSError 属性の上に来ますが、例外がないため、取得できません。
errno は GNU libc のマクロであるため、ctypes を使用すると libc.errno は機能しません。Python 2.6 にはいくつかのアフォーダンスがありますが、Debian は依然として Python 2.5 を使用します。errno を読み取るためだけに C モジュールを純粋な Python プログラムに挿入するのはうんざりします。
errnoにアクセスする方法はありますか?ラップされるライブラリは Linux 専用であるため、Linux 専用のソリューションでも問題ありません。また、失敗する可能性がある間は 1 つのスレッドだけを実行するため、スレッドについて心配する必要もありません。
解決
更新:オンのはPython 2.6 + を、使用<のhref = "https://docs.python.org/3/library/ctypes.html#ctypes.get_errno" のrel = "nofollowをnoreferrer 「> ctypes.get_errno()
を。
パイソン2.5
Belowedコードは(errno
が定義できる方法のpleforaがある、または包括的)信頼できないですが、それはあなたが始められる(または小さな拡張モジュール上の自分の位置を再考すべきである(結局は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())
他のヒント
ここで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)
重要なことは、それ以外の場合は、すでに上書きされることがあります。
、あなたは関数呼び出しの後、できるだけ早く<=>確認するということですctypes.get_errno/set_errno
を提供します。このパッチを使用することができますようにに見えます
http://bugs.python.org/issue1798する
これは実際にリポジトリに適用されたパッチがあります:
http://svn.python.org/view?view=rev&revision=63977 >
それ以外の場合は、リターンはerrnoが、何もしない新しいCモジュールを追加/ /嫌ですが、そう、あなたが使用しているライブラリです。私は自分自身をPythonのパッチ適用に優先してそれを行うだろう。
あきらめおよび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_locationのマジックワードは、一般的なパターンのように見えます。しかし、とだけにerrno の私はかなり失われました。
これがあなたと Jerub が言及していることかどうかはわかりませんが、errno をエクスポートするだけの非常に短い C 拡張機能を作成することもできます。と Python言語インターフェース.
それ以外の場合、この小さなコンパイル済みコードを追加するのは面倒だという意見に私も同意します。
ctypesのは、実際にerrnoを使用しているPythonのC実装を、アクセスするための標準的な方法を提供します。私は(Linux)のシステム以外でこれをテストしていませんが、これは非常に移植する必要があります:
ctypes.c_int.in_dll(ctypes.pythonapi、 "エラー番号")
現在の値を含むc_intのを返す。