Skip to content

Commit 2f2a873

Browse files
committed
feat(utils): ✨ extend HttpRequester constructor to support cache configuration parameters
1 parent 99f9b0d commit 2f2a873

1 file changed

Lines changed: 57 additions & 14 deletions

File tree

rocrate_validator/utils/http.py

Lines changed: 57 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15+
from __future__ import annotations
16+
1517
import atexit
1618
import os
1719
import random
1820
import string
1921
import threading
22+
from typing import Optional
2023

2124
import requests
2225

@@ -34,8 +37,9 @@ class HttpRequester:
3437
_instance = None
3538
_lock = threading.Lock()
3639

37-
def __new__(cls):
40+
def __new__(cls, *args, **kwargs) -> HttpRequester:
3841
if cls._instance is None:
42+
logger.debug(f"Creating instance of {cls.__name__} with args: {args}, kwargs: {kwargs}")
3943
with cls._lock:
4044
if cls._instance is None:
4145
logger.debug(f"Creating instance of {cls.__name__}")
@@ -44,40 +48,59 @@ def __new__(cls):
4448
logger.debug(f"Instance created: {cls._instance.__class__.__name__}")
4549
return cls._instance
4650

47-
def __init__(self):
51+
def __init__(self,
52+
cache_max_age: int = constants.DEFAULT_HTTP_CACHE_MAX_AGE,
53+
cache_path: Optional[str] = None):
54+
logger.debug(f"Initializing instance of {self.__class__.__name__} {self}")
4855
# check if the instance is already initialized
4956
if not hasattr(self, "_initialized"):
5057
# check if the instance is already initialized
5158
with self._lock:
5259
if not getattr(self, "_initialized", False):
5360
# set the initialized flag
5461
self._initialized = False
62+
# store the parameters
63+
try:
64+
logger.debug(f"Setting cache_max_age to {cache_max_age}")
65+
self.cache_max_age = int(cache_max_age)
66+
except ValueError:
67+
raise TypeError("cache_max_age must be an integer")
68+
self.cache_path_prefix = cache_path
69+
# flag to indicate if the cache is permanent or temporary
70+
self.permanent_cache = cache_path is not None
5571
# initialize the session
56-
self.__initialize_session__()
72+
self.__initialize_session__(cache_max_age, cache_path)
5773
# set the initialized flag
5874
self._initialized = True
5975
else:
6076
logger.debug(f"Instance of {self} already initialized")
6177

62-
def __initialize_session__(self):
78+
def __initialize_session__(self, cache_max_age: int, cache_path: Optional[str] = None):
6379
# initialize the session
6480
self.session = None
6581
logger.debug(f"Initializing instance of {self.__class__.__name__}")
6682
assert not self._initialized, "Session already initialized"
6783
# check if requests_cache is installed
6884
# and set up the cached session
6985
try:
70-
if constants.DEFAULT_HTTP_CACHE_TIMEOUT > 0:
86+
if cache_max_age >= 0:
7187
from requests_cache import CachedSession
7288

73-
# Generate a random path for the cache
74-
# to avoid conflicts with other instances
75-
random_suffix = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
89+
# If cache_path is not provided, use the default path prefix
90+
if not cache_path:
91+
# Generate a random path for the cache
92+
# to avoid conflicts with other instances
93+
random_suffix = ''.join(random.choices(string.ascii_letters + string.digits, k=8))
94+
cache_path = constants.DEFAULT_HTTP_CACHE_PATH_PREFIX + f"_{random_suffix}"
95+
logger.debug(f"Using default cache path: {cache_path}")
96+
else:
97+
logger.debug(f"Using provided cache path: {cache_path}")
98+
self.permanent_cache = True
7699
# Initialize the session with a cache
77100
self.session = CachedSession(
78101
# Cache name with random suffix
79-
cache_name=f"{constants.DEFAULT_HTTP_CACHE_PATH_PREFIX}_{random_suffix}",
80-
expire_after=constants.DEFAULT_HTTP_CACHE_TIMEOUT, # Cache expiration time in seconds
102+
cache_name=cache_path,
103+
expire_after=cache_max_age, # Cache expiration time in seconds
81104
backend='sqlite', # Use SQLite backend
82105
allowable_methods=('GET',), # Cache GET
83106
allowable_codes=(200, 302, 404) # Cache responses with these status codes
@@ -86,15 +109,23 @@ def __initialize_session__(self):
86109
logger.warning("requests_cache is not installed. Using requests instead.")
87110
except Exception as e:
88111
logger.error("Error initializing requests_cache: %s", e)
89-
logger.warning("Using requests instead of requests_cache")
90-
# if requests_cache is not installed or an error occurred, use requests
91-
# instead of requests_cache
112+
113+
# if requests_cache is not installed or an error occurred,
114+
# use requests instead of requests_cache
92115
# and create a new session
93116
if not self.session:
94-
logger.debug("Using requests instead of requests_cache")
117+
logger.debug("Cache disabled: using requests instead of requests_cache")
95118
self.session = requests.Session()
96119

97120
def __del__(self):
121+
"""
122+
Destructor to clean up the cache file used by CachedSession.
123+
"""
124+
logger.debug(f"Deleting instance of {self.__class__.__name__}")
125+
if hasattr(self, "permanent_cache") and not self.permanent_cache:
126+
self.cleanup()
127+
128+
def cleanup(self):
98129
"""
99130
Destructor to clean up the cache file used by CachedSession.
100131
"""
@@ -119,3 +150,15 @@ def __getattr__(self, name):
119150
if name.upper() in {"GET", "POST", "PUT", "DELETE", "HEAD", "OPTIONS", "PATCH"}:
120151
return getattr(self.session, name.lower())
121152
raise AttributeError(f"'{self.__class__.__name__}' object has no attribute '{name}'")
153+
154+
@classmethod
155+
def initialize_cache(cls,
156+
cache_max_age: int = constants.DEFAULT_HTTP_CACHE_MAX_AGE,
157+
cache_path: Optional[str] = None) -> HttpRequester:
158+
"""
159+
Initialize the HttpRequester singleton with cache settings.
160+
161+
:param max_age: The maximum age of the cache in seconds.
162+
:param cache_path: The path to the cache directory.
163+
"""
164+
return cls(cache_max_age=cache_max_age, cache_path=cache_path)

0 commit comments

Comments
 (0)