From 259fe41e03bb685448591fe6eaec12945f649ebd Mon Sep 17 00:00:00 2001 From: Alex Huszagh Date: Sat, 7 Sep 2024 12:37:36 -0500 Subject: [PATCH] CI Fix --- example/breeze_theme.py | 81 +++++++++++++++++++---------------------- pyproject.toml | 2 +- 2 files changed, 39 insertions(+), 44 deletions(-) diff --git a/example/breeze_theme.py b/example/breeze_theme.py index fac37d4..6e0ddf8 100644 --- a/example/breeze_theme.py +++ b/example/breeze_theme.py @@ -292,29 +292,19 @@ def macos_supported_version() -> bool: def _get_theme_macos() -> Theme: '''Get the current theme, as light or dark, for the system on macOS.''' - global _theme_macos_impl - if _theme_macos_impl is None: - _theme_macos_impl = _get_theme_macos_impl() - return _theme_macos_impl() - - -def _as_utf8(value: bytes | str) -> bytes: - '''Encode a value to UTF-8''' - return value if isinstance(value, bytes) else value.encode('utf-8') - - -def _register_name(objc: ctypes.CDLL, name: bytes | str) -> None: - '''Register a name within our DLLs.''' - return objc.sel_registerName(_as_utf8(name)) - - -def _get_class(objc: ctypes.CDLL, name: bytes | str) -> 'ctypes._NamedFuncPointer': - '''Get a class by the registered name.''' - return objc.objc_getClass(_as_utf8(name)) - - -def _get_theme_macos_impl() -> ThemeFn: - '''Create the theme callback for macOS.''' + # NOTE: This can segfault on M1 and M2 Macs on Big Sur 11.4+. So, we also try reading + # directly using subprocess. + try: + command = ['defaults', 'read', '-globalDomain', 'AppleInterfaceStyle'] + process = subprocess.run(command, capture_output=True, check=True) + try: + result = process.stdout.decode('utf-8').strip() + return Theme.DARK if result == 'Dark' else Theme.LIGHT + except UnicodeDecodeError: + return Theme.LIGHT + except subprocess.CalledProcessError: + # We can't read these defaults, just try using our libcs + pass # NOTE: We do this so we don't need imports at the global level. try: @@ -333,26 +323,33 @@ def _get_theme_macos_impl() -> ThemeFn: user_defaults = _get_class(objc, 'NSUserDefaults') ns_string = _get_class(objc, 'NSString') - def get_theme_func() -> Theme: - '''Get the theme with all our internal helpers.''' - import faulthandler - faulthandler.enable() - pool = msg(auto_release_pool, _register_name(objc, 'alloc')) -# pool = msg(pool, _register_name(objc, 'init')) -# std_user_defaults = msg(user_defaults, _register_name(objc, 'standardUserDefaults')) + pool = msg(auto_release_pool, _register_name(objc, 'alloc')) + pool = msg(pool, _register_name(objc, 'init')) + std_user_defaults = msg(user_defaults, _register_name(objc, 'standardUserDefaults')) + + key = msg(ns_string, _register_name(objc, "stringWithUTF8String:"), _as_utf8('AppleInterfaceStyle')) + appearance_ns = msg(std_user_defaults, _register_name(objc, 'stringForKey:'), ctypes.c_void_p(key)) + appearance_c = msg(appearance_ns, _register_name(objc, 'UTF8String')) + + out = ctypes.string_at(appearance_c) if appearance_c is not None else None + msg(pool, _register_name(objc, 'release')) + + return Theme.from_string(out.decode('utf-8')) if out is not None else Theme.LIGHT - return Theme.DARK -# TODO: Restore -# key = msg(ns_string, _register_name(objc, "stringWithUTF8String:"), _as_utf8('AppleInterfaceStyle')) -# appearance_ns = msg(std_user_defaults, _register_name(objc, 'stringForKey:'), ctypes.c_void_p(key)) -# appearance_c = msg(appearance_ns, _register_name(objc, 'UTF8String')) -# -# out = ctypes.string_at(appearance_c) if appearance_c is not None else None -# msg(pool, _register_name(objc, 'release')) -# -# return Theme.from_string(out.decode('utf-8')) if out is not None else Theme.LIGHT - return get_theme_func +def _as_utf8(value: bytes | str) -> bytes: + '''Encode a value to UTF-8''' + return value if isinstance(value, bytes) else value.encode('utf-8') + + +def _register_name(objc: ctypes.CDLL, name: bytes | str) -> None: + '''Register a name within our DLLs.''' + return objc.sel_registerName(_as_utf8(name)) + + +def _get_class(objc: ctypes.CDLL, name: bytes | str) -> 'ctypes._NamedFuncPointer': + '''Get a class by the registered name.''' + return objc.objc_getClass(_as_utf8(name)) def _listener_macos(callback: CallbackFn) -> None: @@ -425,8 +422,6 @@ def observeValueForKeyPath_ofObject_change_context_( # pylint: disable=invalid- AppHelper.runConsoleEventLoop() -_theme_macos_impl: ThemeFn | None = None - # endregion # region linux diff --git a/pyproject.toml b/pyproject.toml index c4f0250..fdc39fa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -300,7 +300,7 @@ max-bool-expr = 5 max-branches = 12 # Maximum number of locals for function / method body. -max-locals = 15 +max-locals = 20 # Maximum number of parents for a class (see R0901). max-parents = 7