Blob Blame History Raw
diff --git a/pyudev/_libudev.py b/pyudev/_libudev.py
index efc27c9..7d97d35 100644
--- a/pyudev/_libudev.py
+++ b/pyudev/_libudev.py
@@ -284,6 +284,3 @@ def load_udev_library():
                 if errorchecker:
                     func.errcheck = errorchecker
     return libudev
-
-
-libudev = load_udev_library()
diff --git a/pyudev/_util.py b/pyudev/_util.py
index a99da08..c11b0b2 100644
--- a/pyudev/_util.py
+++ b/pyudev/_util.py
@@ -33,7 +33,6 @@ import os
 import sys
 import stat
 
-from pyudev._libudev import libudev
 
 if sys.version_info[0] == 2:
     from pyudev._py2util import *
@@ -101,7 +100,7 @@ def string_to_bool(value):
     return value == '1'
 
 
-def udev_list_iterate(entry):
+def udev_list_iterate(libudev, entry):
     """
     Iteration helper for udev list entry objects.
 
diff --git a/pyudev/core.py b/pyudev/core.py
index 83d2c7c..5017d80 100644
--- a/pyudev/core.py
+++ b/pyudev/core.py
@@ -35,7 +35,7 @@ except ImportError:
     from pyudev._compat import check_output
 
 from pyudev.device import Device
-from pyudev._libudev import libudev
+from pyudev._libudev import load_udev_library
 from pyudev._util import (ensure_unicode_string, ensure_byte_string,
                           udev_list_iterate, property_value_to_bytes)
 
@@ -89,10 +89,11 @@ class Context(object):
         """
         Create a new context.
         """
-        self._as_parameter_ = libudev.udev_new()
+        self._libudev = load_udev_library()
+        self._as_parameter_ = self._libudev.udev_new()
 
     def __del__(self):
-        libudev.udev_unref(self)
+        self._libudev.udev_unref(self)
 
     @property
     def sys_path(self):
@@ -102,7 +103,7 @@ class Context(object):
         The mount point can be overwritten using the environment variable
         :envvar:`SYSFS_PATH`.  Use this for testing purposes.
         """
-        return ensure_unicode_string(libudev.udev_get_sys_path(self))
+        return ensure_unicode_string(self._libudev.udev_get_sys_path(self))
 
     @property
     def device_path(self):
@@ -111,7 +112,7 @@ class Context(object):
 
         This can be overridden in the udev configuration.
         """
-        return ensure_unicode_string(libudev.udev_get_dev_path(self))
+        return ensure_unicode_string(self._libudev.udev_get_dev_path(self))
 
     @property
     def run_path(self):
@@ -123,7 +124,7 @@ class Context(object):
 
         .. versionadded:: 0.10
         """
-        return ensure_unicode_string(libudev.udev_get_run_path(self))
+        return ensure_unicode_string(self._libudev.udev_get_run_path(self))
 
     @property
     def log_priority(self):
@@ -142,11 +143,11 @@ class Context(object):
 
         .. versionadded:: 0.9
         """
-        return libudev.udev_get_log_priority(self)
+        return self._libudev.udev_get_log_priority(self)
 
     @log_priority.setter
     def log_priority(self, value):
-        libudev.udev_set_log_priority(self, value)
+        self._libudev.udev_set_log_priority(self, value)
 
     def list_devices(self, **kwargs):
         """
@@ -205,10 +206,11 @@ class Enumerator(object):
         if not isinstance(context, Context):
             raise TypeError('Invalid context object')
         self.context = context
-        self._as_parameter_ = libudev.udev_enumerate_new(context)
+        self._as_parameter_ = context._libudev.udev_enumerate_new(context)
+        self._libudev = context._libudev
 
     def __del__(self):
-        libudev.udev_enumerate_unref(self)
+        self._libudev.udev_enumerate_unref(self)
 
     def match(self, **kwargs):
         """
@@ -265,9 +267,9 @@ class Enumerator(object):
 
         Return the instance again.
         """
-        match = (libudev.udev_enumerate_add_match_subsystem
+        match = (self._libudev.udev_enumerate_add_match_subsystem
                  if not nomatch else
-                 libudev.udev_enumerate_add_nomatch_subsystem)
+                 self._libudev.udev_enumerate_add_nomatch_subsystem)
         match(self, ensure_byte_string(subsystem))
         return self
 
@@ -281,7 +283,7 @@ class Enumerator(object):
 
         .. versionadded:: 0.8
         """
-        libudev.udev_enumerate_add_match_sysname(
+        self._libudev.udev_enumerate_add_match_sysname(
             self, ensure_byte_string(sys_name))
         return self
 
@@ -301,7 +303,7 @@ class Enumerator(object):
 
         Return the instance again.
         """
-        libudev.udev_enumerate_add_match_property(
+        self._libudev.udev_enumerate_add_match_property(
             self, ensure_byte_string(property), property_value_to_bytes(value))
         return self
 
@@ -332,9 +334,9 @@ class Enumerator(object):
 
         Return the instance again.
         """
-        match = (libudev.udev_enumerate_add_match_sysattr
+        match = (self._libudev.udev_enumerate_add_match_sysattr
                  if not nomatch else
-                 libudev.udev_enumerate_add_nomatch_sysattr)
+                 self._libudev.udev_enumerate_add_nomatch_sysattr)
         match(self, ensure_byte_string(attribute),
               property_value_to_bytes(value))
         return self
@@ -351,7 +353,7 @@ class Enumerator(object):
 
         .. versionadded:: 0.6
         """
-        libudev.udev_enumerate_add_match_tag(self, ensure_byte_string(tag))
+        self._libudev.udev_enumerate_add_match_tag(self, ensure_byte_string(tag))
         return self
 
     def match_is_initialized(self):
@@ -372,7 +374,7 @@ class Enumerator(object):
 
         .. versionadded:: 0.8
         """
-        libudev.udev_enumerate_add_match_is_initialized(self)
+        self._libudev.udev_enumerate_add_match_is_initialized(self)
         return self
 
     def match_parent(self, parent):
@@ -389,7 +391,7 @@ class Enumerator(object):
 
         .. versionadded:: 0.13
         """
-        libudev.udev_enumerate_add_match_parent(self, parent)
+        self._libudev.udev_enumerate_add_match_parent(self, parent)
         return self
 
     def __iter__(self):
@@ -398,7 +400,7 @@ class Enumerator(object):
 
         Yield :class:`Device` objects.
         """
-        libudev.udev_enumerate_scan_devices(self)
-        entry = libudev.udev_enumerate_get_list_entry(self)
-        for name, _ in udev_list_iterate(entry):
+        self._libudev.udev_enumerate_scan_devices(self)
+        entry = self._libudev.udev_enumerate_get_list_entry(self)
+        for name, _ in udev_list_iterate(self._libudev, entry):
             yield Device.from_sys_path(self.context, name)
diff --git a/pyudev/device.py b/pyudev/device.py
index f9a4325..d5ae3da 100644
--- a/pyudev/device.py
+++ b/pyudev/device.py
@@ -32,7 +32,6 @@ import os
 from collections import Mapping, Container, Iterable
 from datetime import timedelta
 
-from pyudev._libudev import libudev
 from pyudev._util import (ensure_byte_string, ensure_unicode_string,
                           udev_list_iterate, string_to_bool,
                           get_device_type)
@@ -219,7 +218,7 @@ class Device(Mapping):
            Raise :exc:`DeviceNotFoundAtPathError` instead of
            :exc:`NoSuchDeviceError`
         """
-        device = libudev.udev_device_new_from_syspath(
+        device = context._libudev.udev_device_new_from_syspath(
             context, ensure_byte_string(sys_path))
         if not device:
             raise DeviceNotFoundAtPathError(sys_path)
@@ -247,7 +246,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.5
         """
-        device = libudev.udev_device_new_from_subsystem_sysname(
+        device = context._libudev.udev_device_new_from_subsystem_sysname(
             context, ensure_byte_string(subsystem),
             ensure_byte_string(sys_name))
         if not device:
@@ -295,7 +294,7 @@ class Device(Mapping):
         if type not in ('char', 'block'):
             raise ValueError('Invalid type: {0!r}. Must be one of "char" '
                              'or "block".'.format(type))
-        device = libudev.udev_device_new_from_devnum(
+        device = context._libudev.udev_device_new_from_devnum(
             context, ensure_byte_string(type[0]), number)
         if not device:
             raise DeviceNotFoundByNumberError(type, number)
@@ -360,7 +359,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.6
         """
-        device = libudev.udev_device_new_from_environment(context)
+        device = context._libudev.udev_device_new_from_environment(context)
         if not device:
             raise DeviceNotFoundInEnvironmentError()
         return cls(context, device)
@@ -368,9 +367,10 @@ class Device(Mapping):
     def __init__(self, context, _device):
         self.context = context
         self._as_parameter_ = _device
+        self._libudev = context._libudev
 
     def __del__(self):
-        libudev.udev_device_unref(self)
+        self._libudev.udev_device_unref(self)
 
     def __repr__(self):
         return 'Device({0.sys_path!r})'.format(self)
@@ -381,12 +381,12 @@ class Device(Mapping):
         The parent :class:`Device` or ``None``, if there is no parent
         device.
         """
-        parent = libudev.udev_device_get_parent(self)
+        parent = self._libudev.udev_device_get_parent(self)
         if not parent:
             return None
         # the parent device is not referenced, thus forcibly acquire a
         # reference
-        return Device(self.context, libudev.udev_device_ref(parent))
+        return Device(self.context, self._libudev.udev_device_ref(parent))
 
     @property
     def children(self):
@@ -432,12 +432,12 @@ class Device(Mapping):
         subsystem = ensure_byte_string(subsystem)
         if device_type is not None:
             device_type = ensure_byte_string(device_type)
-        parent = libudev.udev_device_get_parent_with_subsystem_devtype(
+        parent = self._libudev.udev_device_get_parent_with_subsystem_devtype(
             self, subsystem, device_type)
         if not parent:
             return None
         # parent device is not referenced, thus forcibly acquire a reference
-        return Device(self.context, libudev.udev_device_ref(parent))
+        return Device(self.context, self._libudev.udev_device_ref(parent))
 
     def traverse(self):
         """
@@ -458,7 +458,8 @@ class Device(Mapping):
         Absolute path of this device in ``sysfs`` including the ``sysfs``
         mount point as unicode string.
         """
-        return ensure_unicode_string(libudev.udev_device_get_syspath(self))
+        return ensure_unicode_string(
+            self._libudev.udev_device_get_syspath(self))
 
     @property
     def device_path(self):
@@ -470,21 +471,24 @@ class Device(Mapping):
         mount point.  However, the path is absolute and starts with a slash
         ``'/'``.
         """
-        return ensure_unicode_string(libudev.udev_device_get_devpath(self))
+        return ensure_unicode_string(
+            self._libudev.udev_device_get_devpath(self))
 
     @property
     def subsystem(self):
         """
         Name of the subsystem this device is part of as unicode string.
         """
-        return ensure_unicode_string(libudev.udev_device_get_subsystem(self))
+        return ensure_unicode_string(
+            self._libudev.udev_device_get_subsystem(self))
 
     @property
     def sys_name(self):
         """
         Device file name inside ``sysfs`` as unicode string.
         """
-        return ensure_unicode_string(libudev.udev_device_get_sysname(self))
+        return ensure_unicode_string(
+            self._libudev.udev_device_get_sysname(self))
 
     @property
     def sys_number(self):
@@ -508,7 +512,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.11
         """
-        number = libudev.udev_device_get_sysnum(self)
+        number = self._libudev.udev_device_get_sysnum(self)
         if number is not None:
             return ensure_unicode_string(number)
 
@@ -529,7 +533,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.10
         """
-        device_type = libudev.udev_device_get_devtype(self)
+        device_type = self._libudev.udev_device_get_devtype(self)
         if device_type is not None:
             return ensure_unicode_string(device_type)
 
@@ -541,7 +545,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.5
         """
-        driver = libudev.udev_device_get_driver(self)
+        driver = self._libudev.udev_device_get_driver(self)
         if driver:
             return ensure_unicode_string(driver)
 
@@ -563,7 +567,7 @@ class Device(Mapping):
            this property is not necessary equal to the ``filename`` given to
            :meth:`from_device_file()`.
         """
-        node = libudev.udev_device_get_devnode(self)
+        node = self._libudev.udev_device_get_devnode(self)
         if node:
             return ensure_unicode_string(node)
 
@@ -591,7 +595,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.11
         """
-        return libudev.udev_device_get_devnum(self)
+        return self._libudev.udev_device_get_devnum(self)
 
     @property
     def is_initialized(self):
@@ -614,7 +618,7 @@ class Device(Mapping):
 
         .. versionadded:: 0.8
         """
-        return bool(libudev.udev_device_get_is_initialized(self))
+        return bool(self._libudev.udev_device_get_is_initialized(self))
 
     @property
     def time_since_initialized(self):
@@ -631,7 +635,8 @@ class Device(Mapping):
 
         .. versionadded:: 0.8
         """
-        microseconds = libudev.udev_device_get_usec_since_initialized(self)
+        microseconds = self._libudev.udev_device_get_usec_since_initialized(
+            self)
         return timedelta(microseconds=microseconds)
 
     @property
@@ -650,8 +655,8 @@ class Device(Mapping):
         The property provides access to all such symbolic links, which were
         created by UDev for this device.
         """
-        devlinks = libudev.udev_device_get_devlinks_list_entry(self)
-        for name, _ in udev_list_iterate(devlinks):
+        devlinks = self._libudev.udev_device_get_devlinks_list_entry(self)
+        for name, _ in udev_list_iterate(self._libudev, devlinks):
             yield ensure_unicode_string(name)
 
     @property
@@ -713,19 +718,16 @@ class Device(Mapping):
         Return a generator yielding the names of all properties of this
         device as unicode strings.
         """
-        properties = libudev.udev_device_get_properties_list_entry(self)
-        for name, _ in udev_list_iterate(properties):
+        properties = self._libudev.udev_device_get_properties_list_entry(self)
+        for name, _ in udev_list_iterate(self._libudev, properties):
             yield ensure_unicode_string(name)
 
     def __len__(self):
         """
         Return the amount of properties defined for this device as integer.
         """
-        properties = libudev.udev_device_get_properties_list_entry(self)
-        i = 0
-        for i, _ in enumerate(udev_list_iterate(properties), start=1):
-            pass
-        return i
+        properties = self._libudev.udev_device_get_properties_list_entry(self)
+        return sum(1 for _ in udev_list_iterate(self._libudev, properties))
 
     def __getitem__(self, property):
         """
@@ -738,7 +740,7 @@ class Device(Mapping):
         :exc:`~exceptions.KeyError`, if the given property is not defined
         for this device.
         """
-        value = libudev.udev_device_get_property_value(
+        value = self._libudev.udev_device_get_property_value(
             self, ensure_byte_string(property))
         if value is None:
             raise KeyError(property)
@@ -814,14 +816,17 @@ class Tags(Iterable, Container):
     def __init__(self, device):
         self.device = device
 
-    if hasattr(libudev, 'udev_device_has_tag'):
-        def _has_tag(self, tag):
-            return bool(libudev.udev_device_has_tag(
+    def _has_tag(self, tag):
+        if hasattr(self._libudev, 'udev_device_has_tag'):
+            return bool(self._libudev.udev_device_has_tag(
                 self.device, ensure_byte_string(tag)))
-    else:
-        def _has_tag(self, tag):
+        else:
             return any(t == tag for t in self)
 
+    @property
+    def _libudev(self):
+        return self.device._libudev
+
     def __contains__(self, tag):
         """
         Check for existence of ``tag``.
@@ -839,8 +844,8 @@ class Tags(Iterable, Container):
 
         Yield each tag as unicode string.
         """
-        tags = libudev.udev_device_get_tags_list_entry(self.device)
-        for tag, _ in udev_list_iterate(tags):
+        tags = self._libudev.udev_device_get_tags_list_entry(self.device)
+        for tag, _ in udev_list_iterate(self._libudev, tags):
             yield ensure_unicode_string(tag)
 
 
@@ -876,29 +881,26 @@ class Attributes(Mapping):
 
     def __init__(self, device):
         self.device = device
+        self._libudev = device._libudev
 
-    if hasattr(libudev, 'udev_device_get_sysattr_list_entry'):
-        @property
-        def _attributes(self):
-            attrs = libudev.udev_device_get_sysattr_list_entry(self.device)
-            for attribute, _ in udev_list_iterate(attrs):
+    def _get_attributes(self):
+        if hasattr(self._libudev, 'udev_device_get_sysattr_list_entry'):
+            attrs = self._libudev.udev_device_get_sysattr_list_entry(
+                self.device)
+            for attribute, _ in udev_list_iterate(self._libudev, attrs):
                 yield ensure_unicode_string(attribute)
-    else:
-        @property
-        def _attributes(self):
+        else:
             sys_path = self.device.sys_path
-            return (fn for fn in os.listdir(sys_path) if
-                    _is_attribute_file(os.path.join(sys_path, fn)) and
-                    fn in self)
+            for filename in os.listdir(sys_path):
+                filepath = os.path.join(sys_path, filename)
+                if _is_attribute_file(filepath):
+                    yield filename
 
     def __len__(self):
         """
         Return the amount of attributes defined.
         """
-        i = 0
-        for i, _ in enumerate(self._attributes, start=1):
-            pass
-        return i
+        return sum(1 for _ in self._get_attributes())
 
     def __iter__(self):
         """
@@ -906,10 +908,10 @@ class Attributes(Mapping):
 
         Yield each attribute name as unicode string.
         """
-        return self._attributes
+        return self._get_attributes()
 
     def __contains__(self, attribute):
-        value = libudev.udev_device_get_sysattr_value(
+        value = self._libudev.udev_device_get_sysattr_value(
             self.device, ensure_byte_string(attribute))
         return value is not None
 
@@ -924,7 +926,7 @@ class Attributes(Mapping):
         :exc:`~exceptions.KeyError`, if the given attribute is not defined
         for this device.
         """
-        value = libudev.udev_device_get_sysattr_value(
+        value = self._libudev.udev_device_get_sysattr_value(
             self.device, ensure_byte_string(attribute))
         if value is None:
             raise KeyError(attribute)
diff --git a/pyudev/monitor.py b/pyudev/monitor.py
index 8153ecc..6a51564 100644
--- a/pyudev/monitor.py
+++ b/pyudev/monitor.py
@@ -36,7 +36,6 @@ import select
 from threading import Thread
 from contextlib import closing
 
-from pyudev._libudev import libudev
 from pyudev._util import ensure_byte_string, ensure_unicode_string, reraise
 
 from pyudev.core import Device
@@ -82,6 +81,7 @@ class Monitor(object):
         self.context = context
         self._as_parameter_ = monitor_p
         self._socket_path = socket_path
+        self._libudev = context._libudev
 
     def _reraise_with_socket_path(self):
         _, exc_value, traceback = sys.exc_info()
@@ -89,7 +89,7 @@ class Monitor(object):
         reraise(exc_value, traceback)
 
     def __del__(self):
-        libudev.udev_monitor_unref(self)
+        self._libudev.udev_monitor_unref(self)
 
     @classmethod
     def from_netlink(cls, context, source='udev'):
@@ -117,7 +117,7 @@ class Monitor(object):
         if source not in ('kernel', 'udev'):
             raise ValueError('Invalid source: {0!r}. Must be one of "udev" '
                              'or "kernel"'.format(source))
-        monitor = libudev.udev_monitor_new_from_netlink(
+        monitor = context._libudev.udev_monitor_new_from_netlink(
             context, ensure_byte_string(source))
         if not monitor:
             raise EnvironmentError('Could not create udev monitor')
@@ -140,7 +140,7 @@ class Monitor(object):
         socket.  Raise :exc:`~exceptions.EnvironmentError`, if the creation of
         the monitor failed.
         """
-        monitor = libudev.udev_monitor_new_from_socket(
+        monitor = context._libudev.udev_monitor_new_from_socket(
             context, ensure_byte_string(socket_path))
         if not monitor:
             raise EnvironmentError('Could not create monitor for socket: '
@@ -154,7 +154,7 @@ class Monitor(object):
         This is really a real file descriptor ;), which can be watched and
         :func:`select.select`\ ed.
         """
-        return libudev.udev_monitor_get_fd(self)
+        return self._libudev.udev_monitor_get_fd(self)
 
     def filter_by(self, subsystem, device_type=None):
         """
@@ -179,9 +179,9 @@ class Monitor(object):
         subsystem = ensure_byte_string(subsystem)
         if device_type:
             device_type = ensure_byte_string(device_type)
-        libudev.udev_monitor_filter_add_match_subsystem_devtype(
+        self._libudev.udev_monitor_filter_add_match_subsystem_devtype(
             self, subsystem, device_type)
-        libudev.udev_monitor_filter_update(self)
+        self._libudev.udev_monitor_filter_update(self)
 
     def filter_by_tag(self, tag):
         """
@@ -202,9 +202,9 @@ class Monitor(object):
         .. versionchanged:: 0.15
            This method can also be after :meth:`enable_receiving()` now
         """
-        libudev.udev_monitor_filter_add_match_tag(
+        self._libudev.udev_monitor_filter_add_match_tag(
             self, ensure_byte_string(tag))
-        libudev.udev_monitor_filter_update(self)
+        self._libudev.udev_monitor_filter_update(self)
 
     def remove_filter(self):
         """
@@ -223,8 +223,8 @@ class Monitor(object):
 
         .. versionadded:: 0.15
         """
-        libudev.udev_monitor_filter_remove(self)
-        libudev.udev_monitor_filter_update(self)
+        self._libudev.udev_monitor_filter_remove(self)
+        self._libudev.udev_monitor_filter_update(self)
 
     def enable_receiving(self):
         """
@@ -240,7 +240,7 @@ class Monitor(object):
            monitor.
         """
         try:
-            libudev.udev_monitor_enable_receiving(self)
+            self._libudev.udev_monitor_enable_receiving(self)
         except EnvironmentError:
             self._reraise_with_socket_path()
 
@@ -272,7 +272,7 @@ class Monitor(object):
         .. _python-prctl: http://packages.python.org/python-prctl
         """
         try:
-            libudev.udev_monitor_set_receive_buffer_size(self, size)
+            self._libudev.udev_monitor_set_receive_buffer_size(self, size)
         except EnvironmentError:
             self._reraise_with_socket_path()
 
@@ -301,13 +301,13 @@ class Monitor(object):
         read.
         """
         try:
-            device_p = libudev.udev_monitor_receive_device(self)
+            device_p = self._libudev.udev_monitor_receive_device(self)
         except EnvironmentError:
             self._reraise_with_socket_path()
         if not device_p:
             raise EnvironmentError('Could not receive device')
         action = ensure_unicode_string(
-            libudev.udev_device_get_action(device_p))
+            self._libudev.udev_device_get_action(device_p))
         return action, Device(self.context, device_p)
 
     def __iter__(self):