git » libfiu » commit 1eb108d

Unify Python 2 and Python 3 bindings

author Alberto Bertogli
2009-05-22 04:24:03 UTC
committer Alberto Bertogli
2009-05-22 04:24:03 UTC
parent 242a627f4da94ddfaa176b0a414e4d93bebeb5af

Unify Python 2 and Python 3 bindings

Signed-off-by: Alberto Bertogli <albertito@blitiri.com.ar>

.gitignore +3 -6
Makefile +8 -12
README +2 -1
bindings/{python3 => python}/fiu.py +0 -0
bindings/{python3 => python}/fiu_ll.c +15 -3
bindings/{python3 => python}/setup.py +8 -1
bindings/python2/fiu.py +0 -75
bindings/python2/fiu_ll.c +0 -191
bindings/python2/setup.py +0 -17

diff --git a/.gitignore b/.gitignore
index 6680650..850b3d0 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,9 +1,6 @@
-bindings/python2/build
-bindings/python2/*.pyc
-bindings/python2/*.pyo
-bindings/python3/build
-bindings/python3/*.pyc
-bindings/python3/*.pyo
+bindings/python/build
+bindings/python/*.pyc
+bindings/python/*.pyo
 libfiu/*.o
 libfiu/libfiu.a
 libfiu/libfiu.pc
diff --git a/Makefile b/Makefile
index f42608a..da76bf2 100644
--- a/Makefile
+++ b/Makefile
@@ -11,22 +11,19 @@ install:
 
 
 python2:
-	cd bindings/python2 && python setup.py build
+	cd bindings/python && python setup.py build
 
 python2_install:
-	cd bindings/python2 && python setup.py install
-
-python2_clean:
-	cd bindings/python2 && rm -rf build/
+	cd bindings/python && python setup.py install
 
 python3:
-	cd bindings/python3 && python3 setup.py build
+	cd bindings/python && python3 setup.py build
 
 python3_install:
-	cd bindings/python3 && python3 setup.py install
+	cd bindings/python && python3 setup.py install
 
-python3_clean:
-	cd bindings/python3 && rm -rf build/
+python_clean:
+	cd bindings/python && rm -rf build/
 
 
 preload:
@@ -35,13 +32,12 @@ preload:
 preload_clean:
 	$(MAKE) -C preload clean
 
-clean: python2_clean python3_clean
+clean: python_clean
 	$(MAKE) -C libfiu clean
 
 
 .PHONY: default all clean libfiu utils \
-	python2 python2_install python2_clean \
-	python3 python3_install python3_clean \
+	python2 python2_install python3 python3_install python_clean \
 	preload preload_clean
 
 
diff --git a/README b/README
index 8ba4ef7..7e8cc80 100644
--- a/README
+++ b/README
@@ -31,7 +31,8 @@ for installing. By default it installs into /usr/local, but you can provide an
 alternative prefix by running "make PREFIX=/my/prefix install".
 
 To build the Python bindings, use "make python2"; to install them you can run
-"make python2_install".
+"make python2_install". For the Python 3 bindings, use "make python3" and
+"make python3_install".
 
 
 Where to report bugs
diff --git a/bindings/python3/fiu.py b/bindings/python/fiu.py
similarity index 100%
rename from bindings/python3/fiu.py
rename to bindings/python/fiu.py
diff --git a/bindings/python3/fiu_ll.c b/bindings/python/fiu_ll.c
similarity index 93%
rename from bindings/python3/fiu_ll.c
rename to bindings/python/fiu_ll.c
index cff30ed..59e3b16 100644
--- a/bindings/python3/fiu_ll.c
+++ b/bindings/python/fiu_ll.c
@@ -1,10 +1,11 @@
 
 /*
- * Python bindings for libfiu
+ * Python 2/3 bindings for libfiu
  * Alberto Bertogli (albertito@blitiri.com.ar)
  *
  * This is the low-level module, used by the python one to construct
- * friendlier objects.
+ * friendlier objects. It support both Python 2 and 3, assuming the constants
+ * PYTHON2 and PYTHON3 are defined accordingly.
  */
 
 #include <Python.h>
@@ -178,24 +179,35 @@ static PyMethodDef fiu_methods[] = {
 	{ NULL }
 };
 
+#ifdef PYTHON3
 static PyModuleDef fiu_module = {
 	PyModuleDef_HEAD_INIT,
 	.m_name = "libfiu",
 	.m_size = -1,
 	.m_methods = fiu_methods,
 };
+#endif
 
-
+#ifdef PYTHON2
+PyMODINIT_FUNC initfiu_ll(void)
+#else
 PyMODINIT_FUNC PyInit_fiu_ll(void)
+#endif
 {
 	PyObject *m;
 
+#ifdef PYTHON2
+	m = Py_InitModule("fiu_ll", fiu_methods);
+#else
 	m = PyModule_Create(&fiu_module);
+#endif
 
 	PyModule_AddIntConstant(m, "FIU_ONETIME", FIU_ONETIME);
 
 	fiu_init(0);
 
+#ifdef PYTHON3
 	return m;
+#endif
 }
 
diff --git a/bindings/python3/setup.py b/bindings/python/setup.py
similarity index 62%
rename from bindings/python3/setup.py
rename to bindings/python/setup.py
index dbdc256..2255064 100644
--- a/bindings/python3/setup.py
+++ b/bindings/python/setup.py
@@ -1,9 +1,16 @@
 
+import sys
 from distutils.core import setup, Extension
 
+if sys.version_info[0] == 2:
+	ver_define = ('PYTHON2', '1')
+elif sys.version_info[0] == 3:
+	ver_define = ('PYTHON3', '1')
+
 fiu_ll = Extension("fiu_ll",
 		libraries = ['fiu'],
-		sources = ['fiu_ll.c'])
+		sources = ['fiu_ll.c'],
+		define_macros = [ver_define])
 
 setup(
 	name = 'fiu',
diff --git a/bindings/python2/fiu.py b/bindings/python2/fiu.py
deleted file mode 100644
index f4e6ece..0000000
--- a/bindings/python2/fiu.py
+++ /dev/null
@@ -1,75 +0,0 @@
-
-"""
-libfiu python wrapper
-
-This module is a wrapper for the libfiu, the fault injection C library.
-
-It provides an almost one-to-one mapping of the libfiu functions, although its
-primary use is to be able to test C code from within Python.
-
-For fault injection in Python, a native library would be more suitable.
-
-See libfiu's manpage for more detailed documentation.
-"""
-
-import fiu_ll as _ll
-
-
-def fail(name):
-	"Returns the failure status of the given point of failure."
-	return _ll.fail(name)
-
-def failinfo(name):
-	"""Returns the information associated with the last failure. Use with
-	care, can be fatal if the point of failure was not enabled via
-	Python."""
-	return _ll.failinfo()
-
-
-# To be sure failinfo doesn't dissapear from under our feet, we keep a
-# name -> failinfo table. See fiu_ll's comments for more details.
-_fi_table = {}
-
-def enable(name, failnum = 1, failinfo = None, flags = 0):
-	"Enables the given point of failure."
-	_fi_table[name] = failnum
-	r = _ll.enable(name, failnum, failinfo, flags)
-	if r != 0:
-		del _fi_table[name]
-		raise RuntimeError, r
-
-def enable_random(name, probability, failnum = 1, failinfo = None, flags = 0):
-	"Enables the given point of failure, with the given probability."
-	_fi_table[name] = failnum
-	r = _ll.enable_random(name, failnum, failinfo, flags, probability)
-	if r != 0:
-		del _fi_table[name]
-		raise RuntimeError, r
-
-def enable_external(name, cb, failnum = 1, flags = 0):
-	"""Enables the given point of failure, leaving the decision whether to
-	fail or not to the given external function, which should return 0 if
-	it is not to fail, or 1 otherwise.
-
-	The cb parameter is a Python function that takes three parameters,
-	name, failnum and flags, with the same values that we receive.
-
-	For technical limitations, enable_external() cannot take
-	failinfo."""
-	# in this case, use the table to prevent the function from
-	# dissapearing
-	_fi_table[name] = cb
-	r = _ll.enable_external(name, failnum, flags, cb)
-	if r != 0:
-		raise RuntimeError, r
-
-def disable(name):
-	"""Disables the given point of failure, undoing the actions of the
-	enable*() functions."""
-	if name in _fi_table:
-		del _fi_table[name]
-	r = _ll.disable(name)
-	if r != 0:
-		raise RuntimeError, r
-
-
diff --git a/bindings/python2/fiu_ll.c b/bindings/python2/fiu_ll.c
deleted file mode 100644
index f0c9a49..0000000
--- a/bindings/python2/fiu_ll.c
+++ /dev/null
@@ -1,191 +0,0 @@
-
-/*
- * Python bindings for libfiu
- * Alberto Bertogli (albertito@blitiri.com.ar)
- *
- * This is the low-level module, used by the python one to construct
- * friendlier objects.
- */
-
-#include <Python.h>
-
-/* Unconditionally enable fiu, otherwise we get fake headers */
-#define FIU_ENABLE 1
-
-#include <fiu.h>
-#include <fiu-control.h>
-
-
-static PyObject *fail(PyObject *self, PyObject *args)
-{
-	char *name;
-	PyObject *rv, *err;
-
-	if (!PyArg_ParseTuple(args, "s:fail", &name))
-		return NULL;
-
-	rv = PyLong_FromLong(fiu_fail(name));
-	err = PyErr_Occurred();
-
-	if (rv == NULL || err != NULL) {
-		Py_XDECREF(rv);
-		return NULL;
-	}
-
-	return rv;
-}
-
-static PyObject *failinfo(PyObject *self, PyObject *args)
-{
-	if (!PyArg_ParseTuple(args, ":failinfo"))
-		return NULL;
-
-	/* We assume failinfo is a python object; but the caller must be
-	 * careful because if it's not, it can get into trouble.
-	 * Note that we DO NOT TOUCH THE RC OF THE OBJECT. It's entirely up to
-	 * the caller to make sure it's still alive. */
-	return (PyObject *) fiu_failinfo();
-}
-
-static PyObject *enable(PyObject *self, PyObject *args)
-{
-	char *name;
-	int failnum;
-	PyObject *failinfo;
-	unsigned int flags;
-
-	if (!PyArg_ParseTuple(args, "siOI:enable", &name, &failnum, &failinfo,
-				&flags))
-		return NULL;
-
-	/* See failinfo()'s comment regarding failinfo's RC */
-	return PyLong_FromLong(fiu_enable(name, failnum, failinfo, flags));
-}
-
-static PyObject *enable_random(PyObject *self, PyObject *args)
-{
-	char *name;
-	int failnum;
-	PyObject *failinfo;
-	unsigned int flags;
-	double probability;
-
-	if (!PyArg_ParseTuple(args, "siOId:enable_random", &name, &failnum,
-				&failinfo, &flags, &probability))
-		return NULL;
-
-	/* See failinfo()'s comment regarding failinfo's RC */
-	return PyLong_FromLong(fiu_enable_random(name, failnum, failinfo,
-				flags, probability));
-}
-
-
-static int external_callback(const char *name, int *failnum, void **failinfo,
-		unsigned int *flags)
-{
-	int rv;
-	PyObject *cbrv;
-	PyObject *args;
-	PyGILState_STATE gil_state;
-
-	/* We need to protect ourselves from the following case:
-	 *  - fiu.enable_callback('x', cb)  (where cb is obviously a Python
-	 *    function)
-	 *  - Later on, call a function p1() inside a python C module, that
-	 *    runs a C function c1() inside
-	 *    Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS
-	 *  - c1() calls fiu_fail("x")
-	 *  - fiu_fail("x") calls external_callback(), and it should run cb()
-	 *  - BUT! It can't run cb(), because it's inside
-	 *    Py_BEGIN_ALLOW_THREADS/Py_END_ALLOW_THREADS so it's not safe to
-	 *    execute any Python code!
-	 *
-	 * The solution is to ensure we're safe to run Python code using
-	 * PyGILState_Ensure()/PyGILState_Release().
-	 */
-
-	gil_state = PyGILState_Ensure();
-	args = Py_BuildValue("(siI)", name, *failnum, *flags);
-	if (args == NULL) {
-		PyGILState_Release(gil_state);
-		return 0;
-	}
-
-	cbrv = PyEval_CallObject(*failinfo, args);
-	Py_DECREF(args);
-
-	if (cbrv == NULL) {
-		PyGILState_Release(gil_state);
-		return 0;
-	}
-
-	/* If PyInt_AsLong() causes an error, it will be handled by the
-	 * PyErr_Occurred() check in fail(), so we don't need to worry about
-	 * it now. */
-	rv = PyInt_AsLong(cbrv);
-	Py_DECREF(cbrv);
-
-	PyGILState_Release(gil_state);
-
-	return rv;
-}
-
-static PyObject *enable_external(PyObject *self, PyObject *args)
-{
-	char *name;
-	int failnum;
-	unsigned int flags;
-	PyObject *py_external_cb;
-
-	if (!PyArg_ParseTuple(args, "siIO:enable_random", &name, &failnum,
-				&flags, &py_external_cb))
-		return NULL;
-
-	if (!PyCallable_Check(py_external_cb)) {
-		PyErr_SetString(PyExc_TypeError, "parameter must be callable");
-		return NULL;
-	}
-
-	/* We use failinfo to store Python's callback function. It'd be nice
-	 * if we could keep both, but it's not easy without keeping state
-	 * inside the C module.
-	 *
-	 * Similar to the way failinfo is handled, we DO NOT TOUCH THE RC OF
-	 * THE EXTERNAL CALLBACK, assuming the caller will take care of making
-	 * sure it doesn't dissapear from beneath us. */
-	return PyLong_FromLong(fiu_enable_external(name, failnum,
-				py_external_cb, flags, external_callback));
-}
-
-static PyObject *disable(PyObject *self, PyObject *args)
-{
-	char *name;
-
-	if (!PyArg_ParseTuple(args, "s:fail", &name))
-		return NULL;
-
-	return PyLong_FromLong(fiu_disable(name));
-}
-
-
-static PyMethodDef fiu_functions[] = {
-	{ "fail", (PyCFunction) fail, METH_VARARGS, NULL },
-	{ "failinfo", (PyCFunction) failinfo, METH_VARARGS, NULL },
-	{ "enable", (PyCFunction) enable, METH_VARARGS, NULL },
-	{ "enable_random", (PyCFunction) enable_random, METH_VARARGS, NULL },
-	{ "enable_external", (PyCFunction) enable_external, METH_VARARGS, NULL },
-	{ "disable", (PyCFunction) disable, METH_VARARGS, NULL },
-	{ NULL }
-};
-
-PyMODINIT_FUNC initfiu_ll(void)
-{
-	PyObject *m;
-
-	m = Py_InitModule("fiu_ll", fiu_functions);
-
-	PyModule_AddIntConstant(m, "FIU_ONETIME", FIU_ONETIME);
-
-	fiu_init(0);
-}
-
diff --git a/bindings/python2/setup.py b/bindings/python2/setup.py
deleted file mode 100644
index dbdc256..0000000
--- a/bindings/python2/setup.py
+++ /dev/null
@@ -1,17 +0,0 @@
-
-from distutils.core import setup, Extension
-
-fiu_ll = Extension("fiu_ll",
-		libraries = ['fiu'],
-		sources = ['fiu_ll.c'])
-
-setup(
-	name = 'fiu',
-	description = "libfiu bindings",
-	author = "Alberto Bertogli",
-	author_email = "albertito@blitiri.com.ar",
-	url = "http://blitiri.com.ar/p/libfiu",
-	py_modules = ['fiu'],
-	ext_modules = [fiu_ll]
-)
-