1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228
|
From: Austin Hurst <mynameisaustinhurst@gmail.com>
Date: Tue, 17 May 2022 13:23:29 -0300
Subject: Clean up organization of dll.py
Origin: upstream, 0.9.12, commit:c742ce6fcd73491f4397bd3f6e6fc99810716f3a
---
sdl2/_internal.py | 25 ++++++++++++
sdl2/dll.py | 120 ++++++++++++++++++++++++++++--------------------------
2 files changed, 88 insertions(+), 57 deletions(-)
create mode 100644 sdl2/_internal.py
diff --git a/sdl2/_internal.py b/sdl2/_internal.py
new file mode 100644
index 0000000..42d3868
--- /dev/null
+++ b/sdl2/_internal.py
@@ -0,0 +1,25 @@
+import warnings
+from ctypes import POINTER, cast, addressof
+
+
+# Defines a type of dict that allows getting (but not setting) keys as attributes
+class AttributeDict(dict):
+ def __getattr__(self, key):
+ return self[key]
+
+
+# Gets a usable pointer from an SDL2 ctypes object
+def get_pointer(ctypes_obj):
+ pointer_type = POINTER(type(ctypes_obj))
+ return cast(addressof(ctypes_obj), pointer_type)
+
+
+# Prints warning without stack or line info
+def prettywarn(msg, warntype):
+ """Prints a suppressable warning without stack or line info."""
+ original = warnings.formatwarning
+ def _pretty_fmt(message, category, filename, lineno, line=None):
+ return "{0}: {1}\n".format(category.__name__, message)
+ warnings.formatwarning = _pretty_fmt
+ warnings.warn(msg, warntype)
+ warnings.formatwarning = original
diff --git a/sdl2/dll.py b/sdl2/dll.py
index 6e30259..9c0eb43 100644
--- a/sdl2/dll.py
+++ b/sdl2/dll.py
@@ -4,16 +4,8 @@ import sys
import warnings
from ctypes import CDLL, POINTER, Structure, c_uint8, cast, addressof
from ctypes.util import find_library
+from ._internal import AttributeDict, prettywarn, get_pointer
-# Prints warning without stack or line info
-def prettywarn(msg, warntype):
- """Prints a suppressable warning without stack or line info."""
- original = warnings.formatwarning
- def _pretty_fmt(message, category, filename, lineno, line=None):
- return "{0}: {1}\n".format(category.__name__, message)
- warnings.formatwarning = _pretty_fmt
- warnings.warn(msg, warntype)
- warnings.formatwarning = original
# Use DLLs from pysdl2-dll, if installed and DLL path not explicitly set
try:
@@ -29,18 +21,50 @@ except ImportError:
__all__ = ["DLL", "nullfunc"]
-# Gets a usable pointer from an SDL2 ctypes object
-def get_pointer(ctypes_obj):
- pointer_type = POINTER(type(ctypes_obj))
- return cast(addressof(ctypes_obj), pointer_type)
+# Wrapper functions for handling calls to missing or unsupported functions
+def nullfunc(*args):
+ """A simple no-op function to be used as dll replacement."""
+ return
+
+def _unavailable(err):
+ """A wrapper that raises a RuntimeError if a function is not supported."""
+ def wrapper(*fargs, **kw):
+ raise RuntimeError(err)
+ return wrapper
+
+def _nonexistent(funcname, func):
+ """A simple wrapper to mark functions and methods as nonexistent."""
+ def wrapper(*fargs, **kw):
+ warnings.warn("%s does not exist" % funcname,
+ category=RuntimeWarning, stacklevel=2)
+ return func(*fargs, **kw)
+ wrapper.__name__ = func.__name__
+ return wrapper
+
+
+# Functions and structures for working with library version numbers
-# For determining DLL version on load
class SDL_version(Structure):
- _fields_ = [("major", c_uint8),
- ("minor", c_uint8),
- ("patch", c_uint8),
- ]
+ # NOTE: defined here so library versions can be detected on load
+ _fields_ = [
+ ("major", c_uint8),
+ ("minor", c_uint8),
+ ("patch", c_uint8),
+ ]
+
+def _version_str_to_int(s):
+ v = [int(n) for n in s.split('.')]
+ return v[0] * 1000 + v[1] * 100 + v[2]
+
+def _version_int_to_str(i):
+ v = str(i)
+ v = [v[0], v[1], str(int(v[2:4]))]
+ return ".".join(v)
+
+def _so_version_num(libname):
+ """Extracts the version number from an .so filename as a list of ints."""
+ return list(map(int, libname.split('.so.')[1].split('.')))
def _using_ms_store_python():
@@ -86,9 +110,11 @@ def _preload_deps(libname, dllpath):
def _findlib(libnames, path=None):
- """Finds SDL2 libraries and returns them in a list, with libraries found in the directory
- optionally specified by 'path' being first (taking precedence) and libraries found in system
- search paths following.
+ """Find libraries with a given name and return their paths in a list.
+
+ If a path is specified, libraries found in that directory will take precedence,
+ with libraries found in system search paths following.
+
"""
platform = sys.platform
@@ -137,6 +163,17 @@ def _findlib(libnames, path=None):
return results
+# Classes for loading libraries and binding ctypes functions
+
+class SDLFunc(object):
+ # A container class for SDL ctypes function definitions
+ def __init__(self, name, args=None, returns=None, added=None):
+ self.name = name
+ self.args = args
+ self.returns = returns
+ self.added = added
+
+
class DLLWarning(Warning):
pass
@@ -168,8 +205,8 @@ class DLL(object):
self._libfile = libfile
self._version = self._get_version(libinfo, self._dll)
if self._version < minversions[libinfo]:
- versionstr = self._version_int_to_str(self._version)
- minimumstr = self._version_int_to_str(minversions[libinfo])
+ versionstr = _version_int_to_str(self._version)
+ minimumstr = _version_int_to_str(minversions[libinfo])
err = "{0} (v{1}) is too old to be used by py-sdl2"
err += " (minimum v{0})".format(minimumstr)
raise RuntimeError(err.format(libfile, versionstr))
@@ -205,9 +242,9 @@ class DLL(object):
function was added, in the format '2.x.x'.
"""
func = getattr(self._dll, funcname, None)
- min_version = self._version_str_to_int(added) if added else None
+ min_version = _version_str_to_int(added) if added else None
if not func:
- versionstr = self._version_int_to_str(self._version)
+ versionstr = _version_int_to_str(self._version)
if min_version and min_version > self._version:
e = "'{0}' requires {1} <= {2}, but the loaded version is {3}."
errmsg = e.format(funcname, self._libname, added, versionstr)
@@ -220,15 +257,6 @@ class DLL(object):
func.restype = returns
return func
- def _version_str_to_int(self, s):
- v = [int(n) for n in s.split('.')]
- return v[0] * 1000 + v[1] * 100 + v[2]
-
- def _version_int_to_str(self, i):
- v = str(i)
- v = [v[0], v[1], str(int(v[2:4]))]
- return ".".join(v)
-
def _get_version(self, libname, dll):
"""Gets the version of the linked SDL library"""
if libname == "SDL2":
@@ -262,30 +290,8 @@ class DLL(object):
return self._version
-def _unavailable(err):
- """A wrapper that raises a RuntimeError if a function is not supported."""
- def wrapper(*fargs, **kw):
- raise RuntimeError(err)
- return wrapper
-def _nonexistent(funcname, func):
- """A simple wrapper to mark functions and methods as nonexistent."""
- def wrapper(*fargs, **kw):
- warnings.warn("%s does not exist" % funcname,
- category=RuntimeWarning, stacklevel=2)
- return func(*fargs, **kw)
- wrapper.__name__ = func.__name__
- return wrapper
-
-
-def _so_version_num(libname):
- """Extracts the version number from an .so filename as a list of ints."""
- return list(map(int, libname.split('.so.')[1].split('.')))
-
-
-def nullfunc(*args):
- """A simple no-op function to be used as dll replacement."""
- return
+# Once the DLL class is defined, try loading the main SDL2 library
try:
dll = DLL("SDL2", ["SDL2", "SDL2-2.0", "SDL2-2.0.0"], os.getenv("PYSDL2_DLL_PATH"))
|