Marcus von Appen avatar Marcus von Appen committed 842824c

- added dll.py, a flexible library loader for ctypes

Comments (0)

Files changed (2)

 ^^^^^^^^^^
 You can simply copy it into your main project. It is recommended to keep the
 hierarchy as it is, so that you put your unittest files into test/ and keep
-all the framework files in test/util.
+all the framework files in test/util. ::
 
   awesomeproject/
     setup.py
 with ``_test.py``. This can be changed in the `gettestfiles()` function in the
 runtests.py file. 
 
-The whole test suite can be executed with a simple module execution:
+The whole test suite can be executed with a simple module execution ::
 
-  python -m awesomepackage.test.util.runtests
+   python -m awesomepackage.test.util.runtests
 
 
 Modules
 Several compatibility helpers to make writing Python code for Python 2.x and
 Python 3.x easier without too many if/else gates.
 
+dll
+---
+A simple ctypes wrapper class for loading shared libraries. 
+
+
 ebs
 ---
 A simple component-based framework.
 
 Within Application.exe (which previously might have been application.py,
 compiled and packaged via py2exe or something similar), you can define
-the resource bundle like:
+the resource bundle like ::
 
-  apppath = os.path.dirname(os.path.abspath(__file__))
-  appresources = Resources(os.path.join(apppath, "resources"))
+   apppath = os.path.dirname(os.path.abspath(__file__))
+   appresources = Resources(os.path.join(apppath, "resources"))
   
-and access your data files like
+and access your data files like ::
 
-  button_image = appresources.get("button.png") 
-  info_file = appresources.get("info.dat")
+   button_image = appresources.get("button.png") 
+   info_file = appresources.get("info.dat")
   
-  # Get textfile1.txt from textcontent.zip
-  textfile1 = appresources.get("textfile1.txt")
+   # Get textfile1.txt from textcontent.zip
+   textfile1 = appresources.get("textfile1.txt")
+"""DLL wrapper"""
+import os
+import sys
+import warnings
+from ctypes import CDLL
+from ctypes.util import find_library
+
+__all__ = ["get_dll_file"]
+
+def _findlib(libnames, path=None):
+    """."""
+    platform = sys.platform
+    if platform in ("win32", "cli"):
+        suffix = ".dll"
+    elif platform == "darwin":
+        suffix = ".dylib"
+    else:
+        suffix = ".so"
+
+    searchfor = libnames
+    if type(libnames) is dict:
+        # different library names for the platforms
+        if platform == "cli" and platform not in libnames:
+            # if not explicitly specified, use the Win32 libs for IronPython
+            platform = "win32"
+        if platform not in libnames:
+            platform = "DEFAULT"
+        searchfor = libnames[platform]
+    results = []
+    if path:
+        for libname in searchfor:
+            dllfile = os.path.join(path, "%s%s" % (libname, suffix))
+            if os.path.exists(dllfile):
+                results.append(dllfile)
+    for libname in searchfor:
+        dllfile = find_library(libname)
+        if dllfile:
+            results.append(dllfile)
+    return results
+
+
+class DLL(object):
+    """A simple wrapper class for loading shared libraries through ctypes.
+
+    The libinfo argument is a descriptive name of the library, that is
+    recommended to be platform neutral, since it is shown to the user on
+    errors. libnames can be a list of shared library names or a dictionary
+    consisting of platform->library name mappings. path is the explicit library
+    path to be used, if any. In case the library is not found in path, ctypes'
+    standard mechanism for finding libraries (ctypes.util.find_library) is
+    used.
+    """
+    def __init__(self, libinfo, libnames, path=None):
+        self._dll = None
+        foundlibs = _findlib(libnames, path)
+        if len(foundlibs) == 0:
+            raise RuntimeError("could not find any library for %s" % libinfo)
+        for libfile in foundlibs:
+            try:
+                self._dll = CDLL(libfile)
+                self._libfile = libfile
+                break
+            except Exception as exc:
+                # Could not load it, silently ignore that issue and move
+                # to the next one.
+                warnings.warn(exc, ImportWarning)
+        if self._dll is None:
+            raise RuntimeError("could not load any library for %s" % libinfo)
+
+    def bind_function(self, funcname, args=None, returns=None, optfunc=None):
+        """Binds the passed argument and return value types to the specified
+        function."""
+        func = getattr(self._dll, funcname, None)
+        if not func:
+            func = optfunc
+        func.argtypes = args
+        func.restype = returns
+        return func
+
+    @property
+    def libfile(self):
+        """Gets the filename of the loaded library."""
+        return self._libfile
+
+
+# Example:
+#
+# dll = DLL("OpenAL", {"win32": ["OpenAL", "OpenAL32", "soft_oal"],
+#                      "darwin": ["OpenAL"],
+#                      "DEFAULT": ["openal"]}, os.getenv("OPENAL_DLL_PATH"))
+#
+# alGetError = dll.bind_function("alGetError", None, ctypes.c_int)
+# ...
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.