1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ from __future__ import annotations
16+
1517import atexit
1618import os
1719import random
1820import string
1921import threading
22+ from typing import Optional
2023
2124import 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