Skip to content

Commit d8a01ba

Browse files
gijzelaerrclaude
andcommitted
Fix mock.patch compatibility with Python 3.11+
- Use mock.patch.object() instead of string-based mock.patch() - Add cache_clear() call before mocking load_library - Fixes AttributeError in TestLibraryIntegration tests The string-based mock.patch() path resolution changed in Python 3.11+ (using pkgutil.resolve_name()), which can fail to find attributes that were imported into a module from elsewhere. See: python/cpython#117860 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent a2421e2 commit d8a01ba

2 files changed

Lines changed: 22 additions & 8 deletions

File tree

tests/test_client.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -947,18 +947,25 @@ def test_set_param(self) -> None:
947947
@pytest.mark.client
948948
class TestLibraryIntegration(unittest.TestCase):
949949
def setUp(self) -> None:
950-
# replace the function load_library with a mock
951-
self.loadlib_patch = mock.patch("snap7.client.load_library")
952-
self.loadlib_func = self.loadlib_patch.start()
950+
# Clear the cache on load_library to ensure mock is used
951+
from snap7.common import load_library
952+
953+
load_library.cache_clear()
953954

954955
# have load_library return another mock
955956
self.mocklib = mock.MagicMock()
956-
self.loadlib_func.return_value = self.mocklib
957957

958958
# have the Cli_Create of the mock return None
959959
self.mocklib.Cli_Create.return_value = None
960960
self.mocklib.Cli_Destroy.return_value = None
961961

962+
# replace the function load_library with a mock
963+
# Use patch.object for Python 3.11+ compatibility (avoids path resolution issues)
964+
import snap7.client
965+
966+
self.loadlib_patch = mock.patch.object(snap7.client, "load_library", return_value=self.mocklib)
967+
self.loadlib_func = self.loadlib_patch.start()
968+
962969
def tearDown(self) -> None:
963970
# restore load_library
964971
self.loadlib_patch.stop()

tests/test_server.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,18 +146,25 @@ def test_set_param(self) -> None:
146146
@pytest.mark.server
147147
class TestLibraryIntegration(unittest.TestCase):
148148
def setUp(self) -> None:
149-
# replace the function load_library with a mock
150-
self.loadlib_patch = mock.patch("snap7.server.load_library")
151-
self.loadlib_func = self.loadlib_patch.start()
149+
# Clear the cache on load_library to ensure mock is used
150+
from snap7.common import load_library
151+
152+
load_library.cache_clear()
152153

153154
# have load_library return another mock
154155
self.mocklib = mock.MagicMock()
155-
self.loadlib_func.return_value = self.mocklib
156156

157157
# have the Srv_Create of the mock return None
158158
self.mocklib.Srv_Create.return_value = None
159159
self.mocklib.Srv_Destroy.return_value = None
160160

161+
# replace the function load_library with a mock
162+
# Use patch.object for Python 3.11+ compatibility (avoids path resolution issues)
163+
import snap7.server
164+
165+
self.loadlib_patch = mock.patch.object(snap7.server, "load_library", return_value=self.mocklib)
166+
self.loadlib_func = self.loadlib_patch.start()
167+
161168
def tearDown(self) -> None:
162169
# restore load_library
163170
self.loadlib_patch.stop()

0 commit comments

Comments
 (0)