Skip to content

Commit ce0ea64

Browse files
committed
Add more logging for libtcod and SDL.
Move protected context closer to tcod.sdl internals.
1 parent 49ebc65 commit ce0ea64

File tree

4 files changed

+70
-32
lines changed

4 files changed

+70
-32
lines changed

tcod/cdef.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,7 @@ float _pycall_path_dest_only(int x1, int y1, int x2, int y2, void* user_data);
1717
void _pycall_sdl_hook(struct SDL_Surface*);
1818

1919
void _pycall_cli_output(void* userdata, const char* output);
20+
21+
// Libtcod log watch function.
22+
void _libtcod_log_watcher(const TCOD_LogMessage* message, void* userdata);
2023
}

tcod/loader.py

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
"""This module handles loading of the libtcod cffi API."""
22
from __future__ import annotations
33

4+
import logging
45
import os
56
import platform
67
import sys
@@ -9,6 +10,8 @@
910

1011
import cffi
1112

13+
logger = logging.getLogger("tcod")
14+
1215
__sdl_version__ = ""
1316

1417
ffi_check = cffi.FFI()
@@ -83,4 +86,18 @@ def __bool__(self) -> bool:
8386

8487
__sdl_version__ = get_sdl_version()
8588

89+
90+
@ffi.def_extern() # type: ignore
91+
def _libtcod_log_watcher(message: Any, userdata: None) -> None:
92+
text = str(ffi.string(message.message), encoding="utf-8")
93+
source = str(ffi.string(message.source), encoding="utf-8")
94+
level = int(message.level)
95+
lineno = int(message.lineno)
96+
logger.log(level, "%s:%d:%s", source, lineno, text)
97+
98+
99+
if lib:
100+
lib.TCOD_set_log_callback(lib._libtcod_log_watcher, ffi.NULL)
101+
lib.TCOD_set_log_level(0)
102+
86103
__all__ = ["ffi", "lib"]

tcod/sdl/__init__.py

Lines changed: 49 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
from __future__ import annotations
22

33
import logging
4+
import sys as _sys
5+
from dataclasses import dataclass
46
from pkgutil import extend_path
7+
from types import TracebackType
58
from typing import Any, Callable, TypeVar
69

710
from tcod.loader import ffi, lib
@@ -10,7 +13,7 @@
1013

1114
T = TypeVar("T")
1215

13-
logger = logging.getLogger(__name__)
16+
logger = logging.getLogger("tcod.sdl")
1417

1518
_LOG_PRIORITY = {
1619
1: logging.DEBUG, # SDL_LOG_PRIORITY_VERBOSE
@@ -21,11 +24,52 @@
2124
6: logging.CRITICAL, # SDL_LOG_PRIORITY_CRITICAL
2225
}
2326

27+
_LOG_CATEGORY = {
28+
int(lib.SDL_LOG_CATEGORY_APPLICATION): "APPLICATION",
29+
int(lib.SDL_LOG_CATEGORY_ERROR): "ERROR",
30+
int(lib.SDL_LOG_CATEGORY_ASSERT): "ASSERT",
31+
int(lib.SDL_LOG_CATEGORY_SYSTEM): "SYSTEM",
32+
int(lib.SDL_LOG_CATEGORY_AUDIO): "AUDIO",
33+
int(lib.SDL_LOG_CATEGORY_VIDEO): "VIDEO",
34+
int(lib.SDL_LOG_CATEGORY_RENDER): "RENDER",
35+
int(lib.SDL_LOG_CATEGORY_INPUT): "INPUT",
36+
int(lib.SDL_LOG_CATEGORY_TEST): "TEST",
37+
int(lib.SDL_LOG_CATEGORY_CUSTOM): "",
38+
}
39+
40+
41+
@dataclass
42+
class _UnraisableHookArgs:
43+
exc_type: type[BaseException]
44+
exc_value: BaseException | None
45+
exc_traceback: TracebackType | None
46+
err_msg: str | None
47+
object: object
48+
49+
50+
class _ProtectedContext:
51+
def __init__(self, obj: object = None) -> None:
52+
self.obj = obj
53+
54+
def __enter__(self) -> None:
55+
pass
56+
57+
def __exit__(
58+
self, exc_type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None
59+
) -> bool:
60+
if exc_type is None:
61+
return False
62+
if _sys.version_info < (3, 8):
63+
return False
64+
_sys.unraisablehook(_UnraisableHookArgs(exc_type, value, traceback, None, self.obj)) # type: ignore[arg-type]
65+
return True
66+
2467

2568
@ffi.def_extern() # type: ignore
26-
def _sdl_log_output_function(_userdata: Any, category: int, priority: int, message: Any) -> None:
69+
def _sdl_log_output_function(_userdata: None, category: int, priority: int, message_p: Any) -> None: # noqa: ANN401
2770
"""Pass logs sent by SDL to Python's logging system."""
28-
logger.log(_LOG_PRIORITY.get(priority, 0), "%i:%s", category, ffi.string(message).decode("utf-8"))
71+
message = str(ffi.string(message_p), encoding="utf-8")
72+
logger.log(_LOG_PRIORITY.get(priority, 0), "%s:%s", _LOG_CATEGORY.get(category, ""), message)
2973

3074

3175
def _get_error() -> str:
@@ -49,6 +93,8 @@ def _check_p(result: Any) -> Any:
4993

5094
if lib._sdl_log_output_function:
5195
lib.SDL_LogSetOutputFunction(lib._sdl_log_output_function, ffi.NULL)
96+
if __debug__:
97+
lib.SDL_LogSetAllPriority(lib.SDL_LOG_PRIORITY_VERBOSE)
5298

5399

54100
def _compiled_version() -> tuple[int, int, int]:

tcod/sdl/audio.py

Lines changed: 1 addition & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@
4747
import sys
4848
import threading
4949
import time
50-
from dataclasses import dataclass
5150
from types import TracebackType
5251
from typing import Any, Callable, Hashable, Iterator
5352

@@ -57,7 +56,7 @@
5756

5857
import tcod.sdl.sys
5958
from tcod.loader import ffi, lib
60-
from tcod.sdl import _check, _get_error
59+
from tcod.sdl import _check, _get_error, _ProtectedContext
6160

6261

6362
def _get_format(format: DTypeLike) -> int:
@@ -561,33 +560,6 @@ class _AudioCallbackUserdata:
561560
device: AudioDevice
562561

563562

564-
@dataclass
565-
class _UnraisableHookArgs:
566-
exc_type: type[BaseException]
567-
exc_value: BaseException | None
568-
exc_traceback: TracebackType | None
569-
err_msg: str | None
570-
object: object
571-
572-
573-
class _ProtectedContext:
574-
def __init__(self, obj: object = None) -> None:
575-
self.obj = obj
576-
577-
def __enter__(self) -> None:
578-
pass
579-
580-
def __exit__(
581-
self, exc_type: type[BaseException] | None, value: BaseException | None, traceback: TracebackType | None
582-
) -> bool:
583-
if exc_type is None:
584-
return False
585-
if sys.version_info < (3, 8):
586-
return False
587-
sys.unraisablehook(_UnraisableHookArgs(exc_type, value, traceback, None, self.obj)) # type: ignore[arg-type]
588-
return True
589-
590-
591563
@ffi.def_extern() # type: ignore
592564
def _sdl_audio_callback(userdata: Any, stream: Any, length: int) -> None: # noqa: ANN401
593565
"""Handle audio device callbacks."""

0 commit comments

Comments
 (0)