From be1943a33f329ca512214f63b3cf4ad4899a3128 Mon Sep 17 00:00:00 2001 From: Sander van Rijn Date: Mon, 11 Mar 2019 21:21:31 +0100 Subject: [PATCH 1/5] Added lru_cache with configurable maxsize to the API call interface --- toggl/utils/config.py | 6 ++++++ toggl/utils/others.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/toggl/utils/config.py b/toggl/utils/config.py index 45e8810..2d8c7c9 100644 --- a/toggl/utils/config.py +++ b/toggl/utils/config.py @@ -261,6 +261,11 @@ class Config(EnvConfigMixin, IniConfigMixin, metaclass=ConfigMeta): """ tz = None + """ + Size of the HTTP API cache. Ignored if cache is disabled. + """ + cache_size = 256 + ENV_MAPPING = { 'api_token': EnvEntry('TOGGL_API_TOKEN', str), 'user_name': EnvEntry('TOGGL_USERNAME', str), @@ -282,6 +287,7 @@ class Config(EnvConfigMixin, IniConfigMixin, metaclass=ConfigMeta): 'time_format': IniEntry('options', str), 'default_wid': IniEntry('options', int), 'retries': IniEntry('options', int), + 'cache_size': IniEntry('options', int), } def __init__(self, config_path=sentinel, read_env=True, **kwargs): # type: (str, bool, **typing.Any) -> None diff --git a/toggl/utils/others.py b/toggl/utils/others.py index 539c49d..7ac66da 100644 --- a/toggl/utils/others.py +++ b/toggl/utils/others.py @@ -1,5 +1,6 @@ import logging import json +from functools import lru_cache from pprint import pformat from time import sleep @@ -144,6 +145,7 @@ def _toggl_request(url, method, data, headers, auth): return response +@lru_cache(maxsize=Config.cache_size) def toggl(url, method, data=None, headers=None, config=None, address=None): """ Makes an HTTP request to toggl.com. Returns the parsed JSON as dict. From ea044ee9603d5097303ddc67848f4836017d43fc Mon Sep 17 00:00:00 2001 From: Sander van Rijn Date: Mon, 11 Mar 2019 21:46:52 +0100 Subject: [PATCH 2/5] caching switch added --- toggl/utils/config.py | 6 ++++++ toggl/utils/others.py | 8 +++++++- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/toggl/utils/config.py b/toggl/utils/config.py index 2d8c7c9..726f393 100644 --- a/toggl/utils/config.py +++ b/toggl/utils/config.py @@ -266,6 +266,11 @@ class Config(EnvConfigMixin, IniConfigMixin, metaclass=ConfigMeta): """ cache_size = 256 + """ + Turns on/off the caching of HTTP API calls. + """ + cache_requests = True + ENV_MAPPING = { 'api_token': EnvEntry('TOGGL_API_TOKEN', str), 'user_name': EnvEntry('TOGGL_USERNAME', str), @@ -288,6 +293,7 @@ class Config(EnvConfigMixin, IniConfigMixin, metaclass=ConfigMeta): 'default_wid': IniEntry('options', int), 'retries': IniEntry('options', int), 'cache_size': IniEntry('options', int), + 'cache_requests': IniEntry('options', bool), } def __init__(self, config_path=sentinel, read_env=True, **kwargs): # type: (str, bool, **typing.Any) -> None diff --git a/toggl/utils/others.py b/toggl/utils/others.py index 7ac66da..f8a7346 100644 --- a/toggl/utils/others.py +++ b/toggl/utils/others.py @@ -145,10 +145,11 @@ def _toggl_request(url, method, data, headers, auth): return response -@lru_cache(maxsize=Config.cache_size) def toggl(url, method, data=None, headers=None, config=None, address=None): """ Makes an HTTP request to toggl.com. Returns the parsed JSON as dict. + Results are cached in an LRU-cache unless disabled through the configuration. + Cache can be cleared by calling `api.others.toggl.cache_clear()' """ from ..toggl import TOGGL_URL @@ -177,3 +178,8 @@ def toggl(url, method, data=None, headers=None, config=None, address=None): # If retries failed then 'e' contains the last Exception/Error, lets re-raise it! raise exception + + +if Config.cache_requests: + # Manual conditional wrapping of the toggl function + toggl = lru_cache(maxsize=Config.cache_size)(toggl) From 7a2633b4848a660f70b00e16c14e72fc01a05d1a Mon Sep 17 00:00:00 2001 From: Sander van Rijn Date: Mon, 11 Mar 2019 22:13:14 +0100 Subject: [PATCH 3/5] initializing cache using Config.factory() rather than default values --- toggl/utils/others.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/toggl/utils/others.py b/toggl/utils/others.py index f8a7346..7a46c13 100644 --- a/toggl/utils/others.py +++ b/toggl/utils/others.py @@ -180,6 +180,6 @@ def toggl(url, method, data=None, headers=None, config=None, address=None): raise exception -if Config.cache_requests: +if Config.factory().cache_requests: # Manual conditional wrapping of the toggl function - toggl = lru_cache(maxsize=Config.cache_size)(toggl) + toggl = lru_cache(maxsize=Config.factory().cache_size)(toggl) From 53fb655dfcb769c47f4ed2d8ccbcaad3fcd07f33 Mon Sep 17 00:00:00 2001 From: Sander van Rijn Date: Mon, 11 Mar 2019 22:15:54 +0100 Subject: [PATCH 4/5] clearing cache upon 'put' call --- toggl/api/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/toggl/api/base.py b/toggl/api/base.py index 281b26e..3fed180 100644 --- a/toggl/api/base.py +++ b/toggl/api/base.py @@ -462,6 +462,8 @@ def save(self, config=None): # type: (utils.Config) -> None self.validate() if self.id is not None: # Update + if config.cache_requests: + utils.toggl.cache_clear() utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'put', self.json(update=True), config=config) self.__change_dict__ = {} # Reset tracking changes else: # Create From 5642afa70dba3f5386c2355ea192112ada795fcc Mon Sep 17 00:00:00 2001 From: Sander van Rijn Date: Mon, 11 Mar 2019 22:24:34 +0100 Subject: [PATCH 5/5] Clearing cache on any 'put', 'post' or 'delete' API call --- toggl/api/base.py | 12 +++++++++--- toggl/api/models.py | 8 ++++++++ toggl/utils/others.py | 3 ++- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/toggl/api/base.py b/toggl/api/base.py index 3fed180..f6264d0 100644 --- a/toggl/api/base.py +++ b/toggl/api/base.py @@ -461,9 +461,10 @@ def save(self, config=None): # type: (utils.Config) -> None self.validate() + if config.cache_requests: + utils.toggl.cache_clear() + if self.id is not None: # Update - if config.cache_requests: - utils.toggl.cache_clear() utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'put', self.json(update=True), config=config) self.__change_dict__ = {} # Reset tracking changes else: # Create @@ -485,7 +486,12 @@ def delete(self, config=None): # type: (utils.Config) -> None if not self.id: raise exceptions.TogglException('This instance has not been saved yet!') - utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'delete', config=config or self._config) + config = config or self._config + + if config.cache_requests: + utils.toggl.cache_clear() + + utils.toggl('/{}/{}'.format(self.get_url(), self.id), 'delete', config=config) self.id = None # Invalidate the object, so when save() is called after delete a new object is created def json(self, update=False): # type: (bool) -> str diff --git a/toggl/api/models.py b/toggl/api/models.py index 154e8a5..b5c4191 100644 --- a/toggl/api/models.py +++ b/toggl/api/models.py @@ -86,6 +86,10 @@ def invite(self, *emails): # type: (str) -> None raise exceptions.TogglValidationException('Supplied email \'{}\' is not valid email!'.format(email)) emails_json = json.dumps({'emails': emails}) + + if self._config.cache_requests: + utils.toggl.cache_clear() + data = utils.toggl("/workspaces/{}/invite".format(self.id), "post", emails_json, config=self._config) if 'notifications' in data and data['notifications']: @@ -333,6 +337,10 @@ def signup(cls, email, password, timezone=None, created_with='TogglCLI', 'timezone': timezone, 'created_with': created_with }}) + + if config.cache_requests: + utils.toggl.cache_clear() + data = utils.toggl("/signups", "post", user_json, config=config) return cls.deserialize(config=config, **data['data']) diff --git a/toggl/utils/others.py b/toggl/utils/others.py index 7a46c13..cdcaf43 100644 --- a/toggl/utils/others.py +++ b/toggl/utils/others.py @@ -149,7 +149,8 @@ def toggl(url, method, data=None, headers=None, config=None, address=None): """ Makes an HTTP request to toggl.com. Returns the parsed JSON as dict. Results are cached in an LRU-cache unless disabled through the configuration. - Cache can be cleared by calling `api.others.toggl.cache_clear()' + Cache can be cleared by calling `api.others.toggl.cache_clear()`. + The cache will be cleared automatically on any 'put', 'post' or 'delete'. """ from ..toggl import TOGGL_URL