From 73f27cb343a5e3206e83fd73a24f5e3304ac9054 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:24:54 -0500 Subject: [PATCH 1/6] An initial attempt to skip collection on macOS API module. Doesn't work because mac_ver doesn't work on newer macs with older Pythons. Ref #529. --- conftest.py | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/conftest.py b/conftest.py index 2bca317c..fff77325 100644 --- a/conftest.py +++ b/conftest.py @@ -1,8 +1,29 @@ +import sys import platform collect_ignore = ["hook-keyring.backend.py"] -if platform.system() != 'Darwin': - collect_ignore.append('keyring/backends/macOS/api.py') + +def macos_api_ignore(): + """ + Starting with macOS 11, the security API becomes + non-viable except on universal2 binaries. + + Ref #525. + """ + + def make_ver(string): + return tuple(map(int, string.split('.'))) + + release, _, _ = platform.mac_ver() + + return ( + platform.system() != 'Darwin' + or make_ver(release) > (11,) + and sys.version_info < (3, 8, 7) + ) + + +collect_ignore.extend(['keyring/backends/macOS/api.py'] * macos_api_ignore()) collect_ignore.append('keyring/devpi_client.py') From eab42e4a6de79a6c9a8454a98d1b0ddc1e75f84b Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:30:59 -0500 Subject: [PATCH 2/6] Use presence of Security.SecItemAdd to detect viable macOS API. Ref #529. --- conftest.py | 18 ++++++------------ 1 file changed, 6 insertions(+), 12 deletions(-) diff --git a/conftest.py b/conftest.py index fff77325..ab0021e0 100644 --- a/conftest.py +++ b/conftest.py @@ -1,5 +1,4 @@ -import sys -import platform +import ctypes collect_ignore = ["hook-keyring.backend.py"] @@ -12,16 +11,11 @@ def macos_api_ignore(): Ref #525. """ - def make_ver(string): - return tuple(map(int, string.split('.'))) - - release, _, _ = platform.mac_ver() - - return ( - platform.system() != 'Darwin' - or make_ver(release) > (11,) - and sys.version_info < (3, 8, 7) - ) + try: + ctypes.CDLL(ctypes.util.find_library('Security')).SecItemAdd + return False + except Exception: + return True collect_ignore.extend(['keyring/backends/macOS/api.py'] * macos_api_ignore()) From 1dfd2fa4d49e3fbccdb09e07dfda31c2b01da659 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:36:02 -0500 Subject: [PATCH 3/6] Only run macOS backend tests when the backend is viable. Fixes #529. Fixes #547. --- keyring/backends/macOS/__init__.py | 2 ++ tests/backends/test_macOS.py | 12 +++++------- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/keyring/backends/macOS/__init__.py b/keyring/backends/macOS/__init__.py index 4a33b8e0..ca91bc98 100644 --- a/keyring/backends/macOS/__init__.py +++ b/keyring/backends/macOS/__init__.py @@ -28,6 +28,8 @@ def priority(cls): """ if platform.system() != 'Darwin': raise RuntimeError("macOS required") + if 'api' not in globals(): + raise RuntimeError("Security API unavailable") return 5 def set_password(self, service, username, password): diff --git a/tests/backends/test_macOS.py b/tests/backends/test_macOS.py index 5d1fd5b0..6dbea271 100644 --- a/tests/backends/test_macOS.py +++ b/tests/backends/test_macOS.py @@ -1,16 +1,14 @@ -import sys - import pytest +import keyring from keyring.testing.backend import BackendBasicTests from keyring.backends import macOS -def is_osx_keychain_supported(): - return sys.platform in ('mac', 'darwin') - - -@pytest.mark.skipif(not is_osx_keychain_supported(), reason="Needs macOS") +@pytest.mark.skipif( + not keyring.backends.macOS.Keyring.viable, + reason="macOS backend not viable", +) class TestOSXKeychain(BackendBasicTests): def init_keyring(self): return macOS.Keyring() From 62e32c356fc86bcd855d2931974b9df17856809e Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:37:45 -0500 Subject: [PATCH 4/6] Rename test to match preferred naming convention for macOS. --- tests/backends/test_macOS.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/backends/test_macOS.py b/tests/backends/test_macOS.py index 6dbea271..5cbbad6a 100644 --- a/tests/backends/test_macOS.py +++ b/tests/backends/test_macOS.py @@ -9,6 +9,6 @@ not keyring.backends.macOS.Keyring.viable, reason="macOS backend not viable", ) -class TestOSXKeychain(BackendBasicTests): +class Test_macOSKeychain(BackendBasicTests): def init_keyring(self): return macOS.Keyring() From a38c5cefda84f6dff78fb9ae61ed9793434b7e89 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:47:32 -0500 Subject: [PATCH 5/6] Update changelog. --- CHANGES.rst | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index db3be646..7efe17bd 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -1,3 +1,14 @@ +v23.3.0 +------- + +* #529: macOS backend is no longer viable if the API module + cannot be loaded. Prevents "symbol not found" errors on + macOS 11 (Big Sur) and later when a "universal2" binary + is not used (available for Python 3.8.7 and later). + +* #547: Tests no longer attempt to run macOS backends even + on macOS when the backend is non-viable. + v23.2.2 ------- From 6dc4103cc72b074ded17f68c823fd292c73b5af2 Mon Sep 17 00:00:00 2001 From: "Jason R. Coombs" Date: Wed, 24 Nov 2021 19:51:23 -0500 Subject: [PATCH 6/6] Add compatibility note for macOS. --- README.rst | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.rst b/README.rst index 9ccea5c1..8ea651f2 100644 --- a/README.rst +++ b/README.rst @@ -54,6 +54,13 @@ install dbus-python as a system package. .. _dbus-python: https://gitlab.freedesktop.org/dbus/dbus-python +Compatibility - macOS +===================== + +macOS keychain support macOS 11 (Big Sur) and later requires Python 3.8.7 +or later with the "universal2" binary. See +`#525 `_ for details. + Using Keyring =============