[PATCH evemu 4/4] py: Add and use wrapper for libevemu calls
Benjamin Tissoires
benjamin.tissoires at gmail.com
Fri Jan 10 16:32:27 PST 2014
Hi Daniel,
On Fri, Jan 10, 2014 at 3:30 AM, Daniel Martin <consume.noise at gmail.com> wrote:
> Introduce a class LibEvemu in base.py, which wraps API calls to
> libevemu, and replace _call()s by using it.
> As this obsoletes the class EvEmuBase, it's removed as well.
>
> v2: Removed tests if functions can be found in the loaded library and
> added tests that the loaded library is static in the class.
>
> Signed-off-by: Daniel Martin <consume.noise at gmail.com>
> ---
> python/evemu/__init__.py | 93 ++++++---------
> python/evemu/base.py | 254 +++++++++++++++++++++++++++++++++++++---
> python/evemu/const.py | 33 ------
> python/evemu/tests/test_base.py | 29 ++++-
> 4 files changed, 292 insertions(+), 117 deletions(-)
>
> diff --git a/python/evemu/__init__.py b/python/evemu/__init__.py
> index f474036..8e725c7 100644
> --- a/python/evemu/__init__.py
> +++ b/python/evemu/__init__.py
> @@ -53,36 +53,28 @@ class Device(object):
> raise TypeError("expected file or file name")
>
> self._is_propfile = self._check_is_propfile(self._file)
> - self._evemu = evemu.base.EvEmuBase()
> self._libc = evemu.base.LibC()
> + self._libevemu = evemu.base.LibEvemu()
> self._uinput = None
>
> - libevemu_new = self._evemu.get_lib().evemu_new
> - libevemu_new.restype = ctypes.c_void_p
> - self._evemu_device = libevemu_new("")
> + self._evemu_device = self._libevemu.evemu_new(b"")
>
> if self._is_propfile:
> fs = self._libc.fdopen(self._file.fileno(), b"r")
> - self._evemu._call(self._evemu.get_lib().evemu_read,
> - self._evemu_device,
> - fs)
> + self._libevemu.evemu_read(self._evemu_device, fs)
> self._uinput = os.open(evemu.const.UINPUT_NODE, os.O_WRONLY)
> self._file = self._create_devnode()
> else:
> - self._evemu._call(self._evemu.get_lib().evemu_extract,
> - self._evemu_device,
> - self._file.fileno())
> + self._libevemu.evemu_extract(self._evemu_device,
> + self._file.fileno())
>
> def __del__(self):
> if hasattr(self, "_is_propfile") and self._is_propfile:
> self._file.close()
> - self._evemu._call(self._evemu.get_lib().evemu_destroy,
> - self._evemu_device, self._uinput)
> + self._libevemu.evemu_destroy(self._evemu_device, self._uinput)
>
> def _create_devnode(self):
> - self._evemu._call(self._evemu.get_lib().evemu_create,
> - self._evemu_device,
> - self._uinput)
> + self._libevemu.evemu_create(self._evemu_device, self._uinput)
> return open(self._find_newest_devnode(self.name), 'r+b', buffering=0)
>
> def _find_newest_devnode(self, target_name):
> @@ -129,9 +121,7 @@ class Device(object):
> raise TypeError("expected file")
>
> fs = self._libc.fdopen(prop_file.fileno(), b"w")
> - self._evemu._call(self._evemu.get_lib().evemu_write,
> - self._evemu_device,
> - fs)
> + self._libevemu.evemu_write(self._evemu_device, fs)
> self._libc.fflush(fs)
>
> def play(self, events_file):
> @@ -146,9 +136,7 @@ class Device(object):
> raise TypeError("expected file")
>
> fs = self._libc.fdopen(events_file.fileno(), b"r")
> - self._evemu._call(self._evemu.get_lib().evemu_play,
> - fs,
> - self._file.fileno())
> + self._libevemu.evemu_play(fs, self._file.fileno())
>
> def record(self, events_file, timeout=10000):
> """
> @@ -163,10 +151,7 @@ class Device(object):
> raise TypeError("expected file")
>
> fs = self._libc.fdopen(events_file.fileno(), b"w")
> - self._evemu._call(self._evemu.get_lib().evemu_record,
> - fs,
> - self._file.fileno(),
> - timeout)
> + self._libevemu.evemu_record(fs, self._file.fileno(), timeout)
> self._libc.fflush(fs)
>
> @property
> @@ -174,8 +159,7 @@ class Device(object):
> """
> Gets the version of the evemu library used to create the Device.
> """
> - return self._evemu._call(self._evemu.get_lib().evemu_get_version,
> - self._evemu_device)
> + return self._libevemu.evemu_get_version(self._evemu_device)
>
> @property
> def devnode(self):
> @@ -189,71 +173,60 @@ class Device(object):
> """
> Gets the name of the input device (as reported by the device).
> """
> - func = self._evemu.get_lib().evemu_get_name
> - func.restype = ctypes.c_char_p
> - return self._evemu._call(func, self._evemu_device)
> + result = self._libevemu.evemu_get_name(self._evemu_device)
> + return result.decode(evemu.const.ENCODING)
>
> @property
> def id_bustype(self):
> """
> Identifies the kernel device bustype.
> """
> - return self._evemu._call(self._evemu.get_lib().evemu_get_id_bustype,
> - self._evemu_device)
> + return self._libevemu.evemu_get_id_bustype(self._evemu_device)
>
> @property
> def id_vendor(self):
> """
> Identifies the kernel device vendor.
> """
> - return self._evemu._call(self._evemu.get_lib().evemu_get_id_vendor,
> - self._evemu_device)
> + return self._libevemu.evemu_get_id_vendor(self._evemu_device)
>
> @property
> def id_product(self):
> """
> Identifies the kernel device product.
> """
> - return self._evemu._call(self._evemu.get_lib().evemu_get_id_product,
> - self._evemu_device)
> + return self._libevemu.evemu_get_id_product(self._evemu_device)
>
> @property
> def id_version(self):
> """
> Identifies the kernel device version.
> """
> - return self._evemu._call(self._evemu.get_lib().evemu_get_id_version,
> - self._evemu_device)
> + return self._libevemu.evemu_get_id_version(self._evemu_device)
>
> def get_abs_minimum(self, event_code):
> - return self._evemu._call(self._evemu.get_lib().evemu_get_abs_minimum,
> - self._evemu_device,
> - int(event_code))
> + return self._libevemu.evemu_get_abs_minimum(self._evemu_device,
> + event_code)
>
> def get_abs_maximum(self, event_code):
> - return self._evemu._call(self._evemu.get_lib().evemu_get_abs_maximum,
> - self._evemu_device,
> - event_code)
> + return self._libevemu.evemu_get_abs_maximum(self._evemu_device,
> + event_code)
>
> def get_abs_fuzz(self, event_code):
> - return self._evemu._call(self._evemu.get_lib().evemu_get_abs_fuzz,
> - self._evemu_device,
> - event_code)
> + return self._libevemu.evemu_get_abs_fuzz(self._evemu_device,
> + event_code)
>
> def get_abs_flat(self, event_code):
> - return self._evemu._call(self._evemu.get_lib().evemu_get_abs_flat,
> - self._evemu_device,
> - event_code)
> + return self._libevemu.evemu_get_abs_flat(self._evemu_device,
> + event_code)
>
> def get_abs_resolution(self, event_code):
> - return self._evemu._call(self._evemu.get_lib().evemu_get_abs_resolution,
> - self._evemu_device,
> - event_code)
> + return self._libevemu.evemu_get_abs_resolution(self._evemu_device,
> + event_code)
>
> def has_prop(self, event_code):
> - return bool(self._evemu._call(self._evemu.get_lib().evemu_has_prop,
> - self._evemu_device,
> - event_code))
> + result = self._libevemu.evemu_has_prop(self._evemu_device, event_code)
> + return bool(result)
>
> def has_event(self, event_type, event_code):
> """
> @@ -267,8 +240,8 @@ class Device(object):
> used to simulate gestures for a higher number of touches than are
> possible with just 2-touch hardware.
> """
> - return bool(self._evemu._call(self._evemu.get_lib().evemu_has_event,
> - self._evemu_device,
> - event_type,
> - event_code))
> + result = self._libevemu.evemu_has_event(self._evemu_device,
> + event_type,
> + event_code)
> + return bool(result)
>
> diff --git a/python/evemu/base.py b/python/evemu/base.py
> index 884c861..b366e2f 100644
> --- a/python/evemu/base.py
> +++ b/python/evemu/base.py
> @@ -160,25 +160,243 @@ class LibC(LibraryWrapper):
> }
>
>
> -class EvEmuBase(object):
> +class LibEvemu(LibraryWrapper):
> """
> - A base wrapper class for the evemu functions, accessed via ctypes.
> + Wrapper for API calls to the evemu library.
> """
> - def __init__(self):
> - self._lib = ctypes.CDLL(evemu.const.LIB, use_errno=True)
> -
> - def _call(self, api_call, *parameters):
> - result = api_call(*parameters)
> - if result < 0 and self.get_c_errno() != 0:
> - raise evemu.exception.ExecutionError("%s: %s" % (
> - api_call.__name__, self.get_c_error()))
> - return result
> -
> - def get_c_errno(self):
> - return ctypes.get_errno()
>
> - def get_c_error(self):
> - return os.strerror(ctypes.get_errno())
> + @staticmethod
> + def _cdll():
> + return ctypes.CDLL(evemu.const.LIB, use_errno=True)
>
> - def get_lib(self):
> - return self._lib
> + _api_prototypes = {
> + #struct evemu_device *evemu_new(const char *name);
> + "evemu_new": {
> + "argtypes": (c_char_p,),
> + "restype": c_void_p,
> + "errcheck": expect_not_none
> + },
> + #void evemu_delete(struct evemu_device *dev);
> + "evemu_delete": {
> + "argtypes": (c_void_p,),
> + "restype": None
> + },
> + #unsigned int evemu_get_version(const struct evemu_device *dev);
> + "evemu_get_version": {
> + "argtypes": (c_void_p,),
> + "restype": c_uint,
> + },
> + #const char *evemu_get_name(const struct evemu_device *dev);
> + "evemu_get_name": {
> + "argtypes": (c_void_p,),
> + "restype": c_char_p,
> + "errcheck": expect_not_none
> + },
> + #void evemu_set_name(struct evemu_device *dev, const char *name);
> + "evemu_set_name": {
> + "argtypes": (c_void_p, c_char_p),
> + "restype": None
> + },
> + #unsigned int evemu_get_id_bustype(const struct evemu_device *dev);
> + "evemu_get_id_bustype": {
> + "argtypes": (c_void_p,),
> + "restype": c_uint
> + },
> + #void evemu_set_id_bustype(struct evemu_device *dev,
> + # unsigned int bustype);
> + "evemu_set_id_bustype": {
> + "argtypes": (c_void_p, c_uint),
> + "restype": None
> + },
> + #unsigned int evemu_get_id_vendor(const struct evemu_device *dev);
> + "evemu_get_id_vendor": {
> + "argtypes": (c_void_p,),
> + "restype": c_uint
> + },
> + #void evemu_set_id_vendor(struct evemu_device *dev,
> + # unsigned int vendor);
> + "evemu_set_id_vendor": {
> + "argtypes": (c_void_p, c_uint),
> + "restype": None
> + },
> + #unsigned int evemu_get_id_product(const struct evemu_device *dev);
> + "evemu_get_id_product": {
> + "argtypes": (c_void_p,),
> + "restype": c_uint
> + },
> + #void evemu_set_id_product(struct evemu_device *dev,
> + # unsigned int product);
> + "evemu_set_id_product": {
> + "argtypes": (c_void_p, c_uint),
> + "restype": None
> + },
> + #unsigned int evemu_get_id_version(const struct evemu_device *dev);
> + "evemu_get_id_version": {
> + "argtypes": (c_void_p,),
> + "restype": c_uint
> + },
> + #void evemu_set_id_version(struct evemu_device *dev,
> + # unsigned int version);
> + "evemu_set_id_version": {
> + "argtypes": (c_void_p, c_uint),
> + "restype": None
> + },
> + #int evemu_get_abs_current_value(const struct evemu_device *dev,
> + # int code);
> + "evemu_get_abs_current_value": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #int evemu_get_abs_minimum(const struct evemu_device *dev, int code);
> + "evemu_get_abs_minimum": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #void evemu_set_abs_minimum(struct evemu_device *dev, int code,
> + # int min);
> + "evemu_set_abs_minimum": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": None
> + },
> + #int evemu_get_abs_maximum(const struct evemu_device *dev, int code);
> + "evemu_get_abs_maximum": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #void evemu_set_abs_maximum(struct evemu_device *dev, int code,
> + # int max);
> + "evemu_set_abs_maximum": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": None
> + },
> + #int evemu_get_abs_fuzz(const struct evemu_device *dev, int code);
> + "evemu_get_abs_fuzz": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #void evemu_set_abs_fuzz(struct evemu_device *dev, int code, int fuzz);
> + "evemu_set_abs_fuzz": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": None,
> + },
> + #int evemu_get_abs_flat(const struct evemu_device *dev, int code);
> + "evemu_get_abs_flat": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #void evemu_set_abs_flat(struct evemu_device *dev, int code, int flat);
> + "evemu_set_abs_flat": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": None
> + },
> + #int evemu_get_abs_resolution(const struct evemu_device *dev,
> + # int code);
> + "evemu_get_abs_resolution": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #void evemu_set_abs_resolution(struct evemu_device *dev, int code,
> + # int res);
> + "evemu_set_abs_resolution": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": None
> + },
> + #int evemu_has_prop(const struct evemu_device *dev, int code);
> + "evemu_has_prop": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #int evemu_has_event(const struct evemu_device *dev, int type,
> + # int code);
> + "evemu_has_event": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #int evemu_has_bit(const struct evemu_device *dev, int type);
> + "evemu_has_bit": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_ge_zero
> + },
> + #int evemu_extract(struct evemu_device *dev, int fd);
> + "evemu_extract": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_write(const struct evemu_device *dev, FILE *fp);
> + "evemu_write": {
> + "argtypes": (c_void_p, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_read(struct evemu_device *dev, FILE *fp);
> + "evemu_read": {
> + "argtypes": (c_void_p, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_gt_zero
> + },
> + #int evemu_write_event(FILE *fp, const struct input_event *ev);
> + "evemu_write_event": {
> + "argtypes": (c_void_p, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_gt_zero
> + },
> + #int evemu_create_event(struct input_event *ev, int type, int code,
> + # int value);
> + "evemu_create_event": {
> + "argtypes": (c_void_p, c_int, c_int, c_int),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_read_event(FILE *fp, struct input_event *ev);
> + "evemu_read_event": {
> + "argtypes": (c_void_p, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_gt_zero
> + },
> + #int evemu_read_event_realtime(FILE *fp, struct input_event *ev,
> + # struct timeval *evtime);
> + "evemu_read_event_realtime": {
> + "argtypes": (c_void_p, c_void_p, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_gt_zero
> + },
> + #int evemu_record(FILE *fp, int fd, int ms);
> + "evemu_record": {
> + "argtypes": (c_void_p, c_int, c_int),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_play_one(int fd, const struct input_event *ev);
> + "evemu_play_one": {
> + "argtypes": (c_int, c_void_p),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_play(FILE *fp, int fd);
> + "evemu_play": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #int evemu_create(struct evemu_device *dev, int fd);
> + "evemu_create": {
> + "argtypes": (c_void_p, c_int),
> + "restype": c_int,
> + "errcheck": expect_eq_zero
> + },
> + #void evemu_destroy(struct evemu_device *dev);
> + "evemu_destroy": {
> + "argtypes": (c_void_p,),
> + "restype": None
> + },
> + }
Thanks for this job.
I would rather prefer having some kind of script which would generate
the dict for us. However, I don't think it is possible to generate
this automatically without spending hours.
How about adding a test during the build which would fail if
"src/libevemu.ver" and _api_prototypes are not matching (at least for
additions/removals). I am thinking of it because I just added 1
function to the API, and I did not updated the python wrapper. I guess
this will happen again in the future, and a failure during compile
would force us to update it accordingly.
Any thoughts on that?
I'll add this to my to-do list for next week I think.
Cheers,
Benjamin
> diff --git a/python/evemu/const.py b/python/evemu/const.py
> index 35f1878..19c507a 100644
> --- a/python/evemu/const.py
> +++ b/python/evemu/const.py
> @@ -2,39 +2,6 @@ LIB = "libevemu.so"
> ENCODING="iso8859-1"
> UINPUT_NODE = "/dev/uinput"
>
> -# The following should be examined every release of evemu
> -API = [
> - "evemu_new",
> - "evemu_delete",
> - "evemu_extract",
> - "evemu_write",
> - "evemu_read",
> - "evemu_write_event",
> - "evemu_record",
> - "evemu_read_event",
> - "evemu_play",
> - "evemu_create",
> - "evemu_destroy",
> - # Device settrs
> - "evemu_set_name",
> - # Device gettrs
> - "evemu_get_version",
> - "evemu_get_name",
> - "evemu_get_id_bustype",
> - "evemu_get_id_vendor",
> - "evemu_get_id_product",
> - "evemu_get_id_version",
> - "evemu_get_abs_minimum",
> - "evemu_get_abs_maximum",
> - "evemu_get_abs_fuzz",
> - "evemu_get_abs_flat",
> - "evemu_get_abs_resolution",
> - # Device hasers
> - "evemu_has_prop",
> - "evemu_has_event",
> - "evemu_has_bit",
> - ]
> -
> event_types = {
> "EV_SYN": 0x00,
> "EV_KEY": 0x01,
> diff --git a/python/evemu/tests/test_base.py b/python/evemu/tests/test_base.py
> index 29bdb15..bc35c73 100644
> --- a/python/evemu/tests/test_base.py
> +++ b/python/evemu/tests/test_base.py
> @@ -7,12 +7,6 @@ import evemu.testing.testcase
>
> class EvEmuBaseTestCase(evemu.testing.testcase.BaseTestCase):
>
> - def test_so_library_found(self):
> - wrapper = evemu.base.EvEmuBase()
> - # Make sure that the library loads
> - self.assertNotEqual(
> - wrapper._lib._name.find("libevemu"), -1)
> -
> def test_libc_found(self):
> lib = evemu.base.LibC._load()
> self.assertNotEqual(lib, None)
> @@ -36,5 +30,28 @@ class EvEmuBaseTestCase(evemu.testing.testcase.BaseTestCase):
>
> self.assertEqual(first._loaded_lib, second._loaded_lib)
>
> + def test_libevemu_found(self):
> + lib = evemu.base.LibEvemu._load()
> + self.assertNotEqual(lib, None)
> + self.assertTrue(lib._name.startswith("libevemu"))
> +
> + def test_libevemu_static_from_load(self):
> + first = evemu.base.LibEvemu._load()
> + self.assertNotEqual(first, None)
> +
> + second = evemu.base.LibEvemu._load()
> + self.assertNotEqual(second, None)
> +
> + self.assertEqual(first, second)
> +
> + def test_libevemu_static_in_object(self):
> + first = evemu.base.LibEvemu()
> + self.assertNotEqual(first, None)
> +
> + second = evemu.base.LibEvemu()
> + self.assertNotEqual(second, None)
> +
> + self.assertEqual(first._loaded_lib, second._loaded_lib)
> +
> if __name__ == "__main__":
> unittest.main()
> --
> 1.8.5.2
>
> _______________________________________________
> Input-tools mailing list
> Input-tools at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/input-tools
More information about the Input-tools
mailing list