From 0fd22addf3581d94ff35ca494a55fd5b75d185a6 Mon Sep 17 00:00:00 2001 From: piekstra Date: Fri, 30 Jan 2026 17:55:52 -0500 Subject: [PATCH] Fix AttributeError when creating TPLinkDeviceManager without credentials Initialize _auth_token to None in __init__ to prevent AttributeError when accessing the attribute before login() is called. This allows users to create a TPLinkDeviceManager without credentials and set the auth token later via set_auth_token(), which is useful for caching tokens to avoid API rate limits. Fixes #75 --- tests/test_device_manager.py | 20 ++++++++++++++++++++ tplinkcloud/device_manager.py | 1 + 2 files changed, 21 insertions(+) diff --git a/tests/test_device_manager.py b/tests/test_device_manager.py index 7461a3d..725e107 100644 --- a/tests/test_device_manager.py +++ b/tests/test_device_manager.py @@ -216,6 +216,26 @@ async def test_auth_no_username_or_password(self, client): ) assert device_manager is not None + @pytest.mark.asyncio + async def test_auth_token_initialized_without_credentials(self, client): + # Regression test for issue #75 + # When creating a device manager without credentials, _auth_token should + # still be initialized to None to avoid AttributeError + device_manager = TPLinkDeviceManager( + username=None, + password=None, + prefetch=True, # This is the default that triggered the bug + cache_devices=True, + tplink_cloud_api_host=os.environ.get('TPLINK_KASA_API_URL'), + verbose=False, + term_id=os.environ.get('TPLINK_KASA_TERM_ID') + ) + # Should be able to access _auth_token without AttributeError + assert device_manager._auth_token is None + # Should be able to set auth token manually + device_manager.set_auth_token('test_token') + assert device_manager._auth_token == 'test_token' + @pytest.mark.asyncio async def test_auth_no_username(self, client): with pytest.raises(ValueError): diff --git a/tplinkcloud/device_manager.py b/tplinkcloud/device_manager.py index faaec01..80e49a9 100644 --- a/tplinkcloud/device_manager.py +++ b/tplinkcloud/device_manager.py @@ -33,6 +33,7 @@ def __init__( self._cache_devices = cache_devices self._cached_devices = None self._term_id = term_id + self._auth_token = None self._tplink_api = TPLinkApi( tplink_cloud_api_host, verbose=self._verbose, term_id=self._term_id)