Skip to content

Commit afafdd5

Browse files
committed
feat(ctypes): handle missing optional symbols gracefully
- Allow ctypes bindings to mark symbols as optional through the `required` flag. - Missing symbols caused by ABI naming differences, API changes, or experimental extensions will no longer break library loading. Optional APIs emit diagnostic warnings and provide runtime unavailable stubs instead. Signed-off-by: JamePeng <jame_peng@sina.com>
1 parent a804dc2 commit afafdd5

1 file changed

Lines changed: 29 additions & 1 deletion

File tree

llama_cpp/_ctypes_extensions.py

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,7 @@ def ctypes_function(
214214
argtypes: List[Any],
215215
restype: Any,
216216
enabled: bool = True,
217+
required: bool = True,
217218
):
218219
"""Bind a Python declaration to one of the requested C symbols.
219220
@@ -222,6 +223,7 @@ def ctypes_function(
222223
argtypes: The ctypes argument types assigned to the C function.
223224
restype: The ctypes return type assigned to the C function.
224225
enabled: Return the original Python declaration when disabled.
226+
required: Raise if symbol is missing. If False, create a runtime unavailable stub.
225227
226228
Raises:
227229
ValueError: If no symbol names are provided.
@@ -252,11 +254,37 @@ def decorator(f: F) -> F:
252254
func.__ctypes_symbol_name__ = symbol_name
253255
return func
254256

255-
raise AttributeError(
257+
message = (
256258
"None of the shared library symbols were found: "
257259
+ ", ".join(symbol_names)
258260
)
259261

262+
if required:
263+
raise AttributeError(message)
264+
265+
# Optional extension API.
266+
# Keep import working when the symbol is unavailable.
267+
print(
268+
"[llama-cpp-python].ctypes_function: WARNING! optional API unavailable\n"
269+
f" symbols: {', '.join(symbol_names)}\n"
270+
f" library: {getattr(lib, '_name', '<unknown>')}"
271+
)
272+
273+
def unavailable(*args, **kwargs):
274+
raise RuntimeError(
275+
"This llama.cpp extension API is unavailable.\n"
276+
f"Required symbol(s): {', '.join(symbol_names)}\n"
277+
f"Library: {getattr(lib, '_name', '<unknown>')}"
278+
)
279+
280+
functools.update_wrapper(unavailable, f)
281+
282+
# Mark unavailable extension API.
283+
unavailable.__ctypes_symbol_name__ = None
284+
unavailable.__ctypes_optional__ = True
285+
286+
return unavailable
287+
260288
return decorator
261289

262290
return ctypes_function

0 commit comments

Comments
 (0)