Skip to content

Commit

Permalink
Make caching of statuses optional and configurable.
Browse files Browse the repository at this point in the history
  • Loading branch information
purple4reina committed Jan 18, 2023
1 parent ed6c0fb commit 38914aa
Show file tree
Hide file tree
Showing 5 changed files with 37 additions and 27 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# CHANGELOG

## Unreleased
### Bug Fixes
+ Make caching of `Gosund.get_device_statuses` optional via opt in and
configurable

## 0.6.1
### Bug Fixes
Expand Down
12 changes: 9 additions & 3 deletions gosundpy/gosund.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,20 @@
class Gosund(object):

def __init__(self, username, password, access_id, access_key, country=1,
endpoint='https://openapi.tuyaus.com'):
endpoint='https://openapi.tuyaus.com', status_cache_seconds=None):
self.api = TuyaOpenAPI(endpoint, access_id, access_key,
auth_type=AuthType.CUSTOM)
resp = self.api.connect(username, password, country)
assert_response_success('connect to api', resp)
self.manager = TuyaDeviceManager(self.api, TuyaOpenMQ(self.api))
self._known_devices = {}

self._status_caching = False
if status_cache_seconds is not None:
self.get_device_statuses = cache_response(
seconds=status_cache_seconds)(self.get_device_statuses)
self._status_caching = True

def get_device(self, device_id):
resp = self.manager.get_device_functions(device_id)
assert_response_success('get device', resp)
Expand All @@ -28,7 +34,6 @@ def get_device_status(self, device_id):
f'unable to find status for device with id "{device_id}"')
return status

@cache_response(seconds=60)
def get_device_statuses(self):
# limit 20 device_ids per api call
resp = self.manager.get_device_list_status(self._known_devices)
Expand All @@ -44,7 +49,8 @@ def _remove_known_device(self, device_id):
self._clear_statuses_cache()

def _clear_statuses_cache(self):
self.get_device_statuses.clear_cache()
if self._status_caching:
self.get_device_statuses.clear_cache()

def send_commands(self, device_id, commands):
resp = self.manager.send_commands(device_id, commands)
Expand Down
30 changes: 8 additions & 22 deletions gosundpy/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,15 @@ def reset(self):

def cache_response(hours=0, minutes=0, seconds=0):
seconds += 60 * 60 * hours + 60 * minutes

class _cache_response(object):

def __init__(self, fn):
# wraps class instance methods only
self.fn = fn
self.cache_key = f'_{fn.__name__}_cache'

def call(self, instance, *args, **kwargs):
def _rate_limit(fn):
@functools.wraps(fn)
def _call(*args, **kwargs):
now = time.time()
cache = getattr(instance, self.cache_key)
if now - cache.last_call < seconds:
return cache.value
cache.set(now, self.fn(instance, *args, **kwargs))
cache.set(now, fn(*args, **kwargs))
return cache.value

def __get__(self, instance, owner):
@functools.wraps(self.fn)
def _call(*args, **kwargs):
return self.call(instance, *args, **kwargs)
if not hasattr(instance, self.cache_key):
setattr(instance, self.cache_key, _timed_cache())
_call.clear_cache = getattr(instance, self.cache_key).reset
return _call

return _cache_response
cache = _timed_cache()
_call.clear_cache = cache.reset
return _call
return _rate_limit
9 changes: 7 additions & 2 deletions tests/unit/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,21 @@ def gosund():
def gosund2():
return _gosund()

@pytest.fixture
def gosund_non_caching():
return _gosund(caching_secs=None)

@responses.activate
def _gosund():
def _gosund(caching_secs=60):
users_login_uri = f'{BASEURL}/users/login'
responses.add(
responses.POST,
users_login_uri,
json={'success': True},
status=200,
)
return Gosund('username', 'password', 'access_id', 'access_key')
return Gosund('username', 'password', 'access_id', 'access_key',
status_cache_seconds=caching_secs)

def patch_get_device(device_id, category):
responses.add(
Expand Down
10 changes: 10 additions & 0 deletions tests/unit/gosund_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,13 @@ def test_gosund_get_device_statuses_cache_per_instance(gosund, gosund2):
resp2 = gosund2.get_device_statuses()
assert resp2 == {}
assert id(resp1) != id(resp2)

@responses.activate
def test_gosund_get_device_statuses_non_caching(gosund_non_caching):
_patch_testing_requests()

gosund_non_caching.get_device(_test_device_id_1)
resp1 = gosund_non_caching.get_device_statuses()
resp2 = gosund_non_caching.get_device_statuses()
assert resp1 == {_test_device_id_1: _test_status_1}
assert id(resp1) != id(resp2)

0 comments on commit 38914aa

Please sign in to comment.