tquota.Quota
==========================================================
Quota Monitoring for Cloud Environments
Created on: Tue May 11, 2021, 13:00:30 Last updated: Wed Oct 16, 2024, 13:00:30
Author: Abdussalam Aljbri Emails: mr.aljbri@gmail.com, mr.aljbri@qq.com Project GitHub: https://github.com/aljbri/tquota Version: 0.0.2 License: MIT License
Description:
This script implements the Quota class, designed to monitor and manage session time limits in cloud environments
like Kaggle or Colab with quota restrictions. It helps in tracking session time and takes action based on predefined
quota and buffer times (gap times). The class provides automatic adjustment of gap times based on average execution
time during operation.
Change Log:
v0.0.3 - Updated on Wed Oct 16, 2024
- Introduced dynamic gap time (
autooption) based on average execution times. - Added logging functionality to log remaining time.
- Improved time validation to handle improper inputs.
- Enhanced time format support, now allowing conversions from strings like '1h', '30m', '5s'.
- Refactored internal code structure for readability.
- Introduced automatic performance monitoring to calculate execution time per loop iteration.
v0.0.2 - Initial implementation (Tue May 12, 2021)
- Fix major error in previous versions.
v0.0.1 - Initial implementation (Tue May 11, 2021)
- Basic
Quotaclass to track remaining session time. - Static gap time support.
- Basic time formatting and conversion.
Usage:
For usage examples, refer to the class-level docstring of Quota.
1# -*- coding: utf-8 -*- 2""" 3========================================================== 4 Quota Monitoring for Cloud Environments 5========================================================== 6 7Created on: Tue May 11, 2021, 13:00:30 8Last updated: Wed Oct 16, 2024, 13:00:30 9 10Author: Abdussalam Aljbri 11Emails: mr.aljbri@gmail.com, mr.aljbri@qq.com 12Project GitHub: https://github.com/aljbri/tquota 13Version: 0.0.2 14License: MIT License 15 16Description: 17------------- 18This script implements the `Quota` class, designed to monitor and manage session time limits in cloud environments 19like Kaggle or Colab with quota restrictions. It helps in tracking session time and takes action based on predefined 20quota and buffer times (gap times). The class provides automatic adjustment of gap times based on average execution 21time during operation. 22 23Change Log: 24----------- 25v0.0.3 - Updated on Wed Oct 16, 2024 26 - Introduced dynamic gap time (`auto` option) based on average execution times. 27 - Added logging functionality to log remaining time. 28 - Improved time validation to handle improper inputs. 29 - Enhanced time format support, now allowing conversions from strings like '1h', '30m', '5s'. 30 - Refactored internal code structure for readability. 31 - Introduced automatic performance monitoring to calculate execution time per loop iteration. 32 33v0.0.2 - Initial implementation (Tue May 12, 2021) 34 - Fix major error in previous versions. 35 36v0.0.1 - Initial implementation (Tue May 11, 2021) 37 - Basic `Quota` class to track remaining session time. 38 - Static gap time support. 39 - Basic time formatting and conversion. 40 41Usage: 42------ 43For usage examples, refer to the class-level docstring of `Quota`. 44""" 45 46import re 47import logging 48from timeit import default_timer 49 50 51class Quota: 52 """ 53 Monitors session time limits in cloud environments with quota limitations (e.g., Kaggle, Colab). 54 55 This class allows users to set a quota time and a gap time, with options for automatic gap time adjustment 56 based on the average execution time of operations within a loop. It can log remaining time and check if 57 the time limits are reached. 58 59 Time Format: 60 The time format must be passed as a string combining digits and a single character representing the time unit: 61 - 's' for seconds 62 - 'm' for minutes 63 - 'h' for hours 64 - 'd' for days 65 66 Examples: 67 - '30s' for 30 seconds 68 - '5m' for 5 minutes 69 - '2h' for 2 hours 70 - '1d' for 1 day 71 72 If an invalid format is provided, a ValueError will be raised. 73 74 Parameters: 75 ----------- 76 - quota_time (str): 77 Time quota for the session (e.g., '1h' for 1 hour, '30m' for 30 minutes). 78 This is initially provided as a string and is internally converted to seconds. 79 Default is '6h'. 80 - gap_time (str): 81 Time buffer before the quota ends to trigger actions. 82 Set to 'auto' for automatic detection based on average execution time. 83 Internally converted to seconds. 84 Default is 'auto'. 85 - enable_logging (bool, optional): 86 Whether to enable logging or not. Default is False. 87 88 Raises: 89 ----------- 90 - ValueError: 91 - If the `quota_time` or `gap_time` format is invalid. This occurs when the time strings are not formatted correctly 92 (e.g., not containing valid time units like 's', 'm', 'h', 'd'). 93 - If the `quota_time` is less than or equal to zero. A quota time must be a positive value in seconds. 94 - If the `gap_time` is greater than or equal to the `quota_time`. The gap time should be smaller than the quota time to make sense. 95 - TypeError: 96 - If a non-string value is provided for `quota_time` or `gap_time`. Both `quota_time` and `gap_time` must be strings to be processed. 97 - AttributeError: 98 - If an attempt is made to access properties or methods without proper initialization of internal values (such as accessing `execution_times` before an operation). 99 100 Properties: 101 ----------- 102 - start_time: The timestamp when the `Quota` instance is initialized (in seconds from `default_timer`). 103 - quota_time: Total session quota time in seconds, converted from the input string (e.g., '1h' → 3600). 104 - auto_gap_time: Flag to indicate whether gap time is set to 'auto', allowing dynamic adjustment. 105 - gap_time: The buffer time before the quota ends. Can be statically set (manual time in seconds) or dynamically adjusted if 'auto'. 106 - enable_logging: Whether to log the remaining time to the console. 107 - execution_times: List of execution times (in seconds) for each loop iteration, used to calculate average execution time. 108 - total_execution_time: The sum of all execution times, used for calculating the dynamic gap time. 109 - last_execution_time: Timestamp of the last completed loop iteration (in seconds). 110 """ 111 112 def __init__(self, quota_time='6h', gap_time='auto', enable_logging=False): 113 self.start_time = default_timer() 114 self.quota_time = self._to_seconds(quota_time) 115 116 # Initialize gap time based on input, either as seconds or 0.0001 if 'auto'. 117 self.auto_gap_time = gap_time in ['a', 'auto'] 118 self.gap_time = 0.0001 if self.auto_gap_time else self._to_seconds(gap_time) 119 120 # Validate times 121 self._validate_times() 122 123 # Initialize logging if enabled 124 self.enable_logging = enable_logging 125 if self.enable_logging: 126 logging.basicConfig(level=logging.INFO) 127 128 # Initialize execution times tracker. 129 self.execution_times = [] # To track execution times 130 self.total_execution_time = 0.0 # To accumulate execution times 131 self.last_execution_time = default_timer() # Initialize last execution time 132 133 def hastime(self): 134 """ 135 Checks if the session still has time before the gap time is reached. 136 137 Returns: 138 ------- 139 bool: True if there is enough time left in the session, False otherwise. 140 """ 141 self._update_gap_time() # Update gap time based on execution history 142 elapsed_time = self._remaining_time() 143 return elapsed_time >= self.gap_time 144 145 def time_up(self): 146 """ 147 Checks if the session has reached or exceeded the quota time. 148 149 Returns: 150 ------- 151 bool: True if the quota time has been exceeded, False otherwise. 152 """ 153 self._update_gap_time() # Update gap time based on execution history 154 remained_time = self._remaining_time() 155 return remained_time < self.gap_time 156 157 def remaining_time(self): 158 """ 159 Returns the remaining time in a human-readable format. 160 161 Returns: 162 ------- 163 str: Remaining time formatted as "xh:xm:xs". 164 """ 165 return self._format_time(self._remaining_time()) 166 167 def log_remaining_time(self): 168 """ 169 Logs the remaining time to the console if logging is enabled. 170 171 Logs: 172 ---- 173 str: Remaining time message if logging is enabled. 174 """ 175 if self.enable_logging: 176 logging.info("Remaining time before quota is reached: {}".format(self.remaining_time())) 177 178 def _remaining_time(self): 179 """ 180 Calculates the remaining time in seconds. 181 182 Returns: 183 int: Remaining time in seconds. 184 """ 185 elapsed_time = self.quota_time - (default_timer() - self.start_time) 186 return max(elapsed_time, 0) 187 188 def _to_seconds(self, wTime): 189 """ 190 Converts a time string into seconds (e.g., '1h' -> 3600). 191 192 Args: 193 wTime: A string representing the time in the format '1h', '30m', '5s', etc. 194 195 Returns: 196 float: Time in seconds. 197 198 Raises: 199 ValueError: If the time format is invalid. 200 """ 201 pattern = r'^(\d+)([smhd])$' 202 match = re.match(pattern, wTime.lower()) 203 if not match: 204 raise ValueError("Invalid time format: '{}'. Use format like '1h', '30m', '5s'.".format(wTime)) 205 206 time_value, unit = match.groups() 207 time_value = int(time_value) 208 unit_seconds = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400} 209 210 if time_value <= 0: 211 raise ValueError("Time value must be greater than zero: '{}'".format(wTime)) 212 213 return time_value * unit_seconds[unit] 214 215 def _format_time(self, seconds): 216 """ 217 Converts seconds into a human-readable time format. 218 219 Args: 220 seconds: Time in seconds. 221 222 Returns: 223 str: A human-readable time string in the format "Xh Xm Xs". 224 """ 225 h, rem = divmod(seconds, 3600) 226 m, s = divmod(rem, 60) 227 return "{}h:{}m:{}s".format(int(h), int(m), int(s)) 228 229 def _validate_times(self): 230 """ 231 Validates that the quota time and gap time are logically consistent. 232 233 Raises: 234 ValueError: If gap time >= quota time or if either time is <= 0. 235 """ 236 if self.gap_time >= self.quota_time: 237 raise ValueError("Gap time must be smaller than the quota time.") 238 if self.quota_time <= 0: 239 raise ValueError("Quota time must be greater than 0.") 240 if self.gap_time <= 0: 241 raise ValueError("Gap time must be greater than 0.") 242 243 def _update_gap_time(self): 244 """ 245 Updates the gap time dynamically based on the average execution time, if `auto` mode is enabled. 246 247 It calculates the time taken since the last operation and updates the gap time accordingly. 248 """ 249 current_time = default_timer() # Get the current time 250 execution_time = current_time - self.last_execution_time # Calculate time since last update 251 self.execution_times.append(execution_time) # Record the execution time 252 self.total_execution_time += execution_time # Update total execution time 253 254 # Update gap_time to average execution time if set to 'auto' and there are recorded times 255 if self.auto_gap_time and self.execution_times: 256 execution_time_average = self.total_execution_time / len(self.execution_times) 257 self.gap_time = execution_time_average # Set gap_time to average in seconds 258 259 self.last_execution_time = current_time # Update the last execution time for the next call 260 261 def _default_action(self): 262 """ 263 Default action to take when the quota time is up. 264 265 Currently, this just logs a message if logging is enabled, but can be extended for future functionality. 266 """ 267 if self.enable_logging: 268 logging.info("Quota time reached. Executing default action.")
52class Quota: 53 """ 54 Monitors session time limits in cloud environments with quota limitations (e.g., Kaggle, Colab). 55 56 This class allows users to set a quota time and a gap time, with options for automatic gap time adjustment 57 based on the average execution time of operations within a loop. It can log remaining time and check if 58 the time limits are reached. 59 60 Time Format: 61 The time format must be passed as a string combining digits and a single character representing the time unit: 62 - 's' for seconds 63 - 'm' for minutes 64 - 'h' for hours 65 - 'd' for days 66 67 Examples: 68 - '30s' for 30 seconds 69 - '5m' for 5 minutes 70 - '2h' for 2 hours 71 - '1d' for 1 day 72 73 If an invalid format is provided, a ValueError will be raised. 74 75 Parameters: 76 ----------- 77 - quota_time (str): 78 Time quota for the session (e.g., '1h' for 1 hour, '30m' for 30 minutes). 79 This is initially provided as a string and is internally converted to seconds. 80 Default is '6h'. 81 - gap_time (str): 82 Time buffer before the quota ends to trigger actions. 83 Set to 'auto' for automatic detection based on average execution time. 84 Internally converted to seconds. 85 Default is 'auto'. 86 - enable_logging (bool, optional): 87 Whether to enable logging or not. Default is False. 88 89 Raises: 90 ----------- 91 - ValueError: 92 - If the `quota_time` or `gap_time` format is invalid. This occurs when the time strings are not formatted correctly 93 (e.g., not containing valid time units like 's', 'm', 'h', 'd'). 94 - If the `quota_time` is less than or equal to zero. A quota time must be a positive value in seconds. 95 - If the `gap_time` is greater than or equal to the `quota_time`. The gap time should be smaller than the quota time to make sense. 96 - TypeError: 97 - If a non-string value is provided for `quota_time` or `gap_time`. Both `quota_time` and `gap_time` must be strings to be processed. 98 - AttributeError: 99 - If an attempt is made to access properties or methods without proper initialization of internal values (such as accessing `execution_times` before an operation). 100 101 Properties: 102 ----------- 103 - start_time: The timestamp when the `Quota` instance is initialized (in seconds from `default_timer`). 104 - quota_time: Total session quota time in seconds, converted from the input string (e.g., '1h' → 3600). 105 - auto_gap_time: Flag to indicate whether gap time is set to 'auto', allowing dynamic adjustment. 106 - gap_time: The buffer time before the quota ends. Can be statically set (manual time in seconds) or dynamically adjusted if 'auto'. 107 - enable_logging: Whether to log the remaining time to the console. 108 - execution_times: List of execution times (in seconds) for each loop iteration, used to calculate average execution time. 109 - total_execution_time: The sum of all execution times, used for calculating the dynamic gap time. 110 - last_execution_time: Timestamp of the last completed loop iteration (in seconds). 111 """ 112 113 def __init__(self, quota_time='6h', gap_time='auto', enable_logging=False): 114 self.start_time = default_timer() 115 self.quota_time = self._to_seconds(quota_time) 116 117 # Initialize gap time based on input, either as seconds or 0.0001 if 'auto'. 118 self.auto_gap_time = gap_time in ['a', 'auto'] 119 self.gap_time = 0.0001 if self.auto_gap_time else self._to_seconds(gap_time) 120 121 # Validate times 122 self._validate_times() 123 124 # Initialize logging if enabled 125 self.enable_logging = enable_logging 126 if self.enable_logging: 127 logging.basicConfig(level=logging.INFO) 128 129 # Initialize execution times tracker. 130 self.execution_times = [] # To track execution times 131 self.total_execution_time = 0.0 # To accumulate execution times 132 self.last_execution_time = default_timer() # Initialize last execution time 133 134 def hastime(self): 135 """ 136 Checks if the session still has time before the gap time is reached. 137 138 Returns: 139 ------- 140 bool: True if there is enough time left in the session, False otherwise. 141 """ 142 self._update_gap_time() # Update gap time based on execution history 143 elapsed_time = self._remaining_time() 144 return elapsed_time >= self.gap_time 145 146 def time_up(self): 147 """ 148 Checks if the session has reached or exceeded the quota time. 149 150 Returns: 151 ------- 152 bool: True if the quota time has been exceeded, False otherwise. 153 """ 154 self._update_gap_time() # Update gap time based on execution history 155 remained_time = self._remaining_time() 156 return remained_time < self.gap_time 157 158 def remaining_time(self): 159 """ 160 Returns the remaining time in a human-readable format. 161 162 Returns: 163 ------- 164 str: Remaining time formatted as "xh:xm:xs". 165 """ 166 return self._format_time(self._remaining_time()) 167 168 def log_remaining_time(self): 169 """ 170 Logs the remaining time to the console if logging is enabled. 171 172 Logs: 173 ---- 174 str: Remaining time message if logging is enabled. 175 """ 176 if self.enable_logging: 177 logging.info("Remaining time before quota is reached: {}".format(self.remaining_time())) 178 179 def _remaining_time(self): 180 """ 181 Calculates the remaining time in seconds. 182 183 Returns: 184 int: Remaining time in seconds. 185 """ 186 elapsed_time = self.quota_time - (default_timer() - self.start_time) 187 return max(elapsed_time, 0) 188 189 def _to_seconds(self, wTime): 190 """ 191 Converts a time string into seconds (e.g., '1h' -> 3600). 192 193 Args: 194 wTime: A string representing the time in the format '1h', '30m', '5s', etc. 195 196 Returns: 197 float: Time in seconds. 198 199 Raises: 200 ValueError: If the time format is invalid. 201 """ 202 pattern = r'^(\d+)([smhd])$' 203 match = re.match(pattern, wTime.lower()) 204 if not match: 205 raise ValueError("Invalid time format: '{}'. Use format like '1h', '30m', '5s'.".format(wTime)) 206 207 time_value, unit = match.groups() 208 time_value = int(time_value) 209 unit_seconds = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400} 210 211 if time_value <= 0: 212 raise ValueError("Time value must be greater than zero: '{}'".format(wTime)) 213 214 return time_value * unit_seconds[unit] 215 216 def _format_time(self, seconds): 217 """ 218 Converts seconds into a human-readable time format. 219 220 Args: 221 seconds: Time in seconds. 222 223 Returns: 224 str: A human-readable time string in the format "Xh Xm Xs". 225 """ 226 h, rem = divmod(seconds, 3600) 227 m, s = divmod(rem, 60) 228 return "{}h:{}m:{}s".format(int(h), int(m), int(s)) 229 230 def _validate_times(self): 231 """ 232 Validates that the quota time and gap time are logically consistent. 233 234 Raises: 235 ValueError: If gap time >= quota time or if either time is <= 0. 236 """ 237 if self.gap_time >= self.quota_time: 238 raise ValueError("Gap time must be smaller than the quota time.") 239 if self.quota_time <= 0: 240 raise ValueError("Quota time must be greater than 0.") 241 if self.gap_time <= 0: 242 raise ValueError("Gap time must be greater than 0.") 243 244 def _update_gap_time(self): 245 """ 246 Updates the gap time dynamically based on the average execution time, if `auto` mode is enabled. 247 248 It calculates the time taken since the last operation and updates the gap time accordingly. 249 """ 250 current_time = default_timer() # Get the current time 251 execution_time = current_time - self.last_execution_time # Calculate time since last update 252 self.execution_times.append(execution_time) # Record the execution time 253 self.total_execution_time += execution_time # Update total execution time 254 255 # Update gap_time to average execution time if set to 'auto' and there are recorded times 256 if self.auto_gap_time and self.execution_times: 257 execution_time_average = self.total_execution_time / len(self.execution_times) 258 self.gap_time = execution_time_average # Set gap_time to average in seconds 259 260 self.last_execution_time = current_time # Update the last execution time for the next call 261 262 def _default_action(self): 263 """ 264 Default action to take when the quota time is up. 265 266 Currently, this just logs a message if logging is enabled, but can be extended for future functionality. 267 """ 268 if self.enable_logging: 269 logging.info("Quota time reached. Executing default action.")
Monitors session time limits in cloud environments with quota limitations (e.g., Kaggle, Colab).
This class allows users to set a quota time and a gap time, with options for automatic gap time adjustment based on the average execution time of operations within a loop. It can log remaining time and check if the time limits are reached.
Time Format: The time format must be passed as a string combining digits and a single character representing the time unit: - 's' for seconds - 'm' for minutes - 'h' for hours - 'd' for days
Examples:
- '30s' for 30 seconds
- '5m' for 5 minutes
- '2h' for 2 hours
- '1d' for 1 day
If an invalid format is provided, a ValueError will be raised.
Parameters:
- quota_time (str): Time quota for the session (e.g., '1h' for 1 hour, '30m' for 30 minutes). This is initially provided as a string and is internally converted to seconds. Default is '6h'.
- gap_time (str): Time buffer before the quota ends to trigger actions. Set to 'auto' for automatic detection based on average execution time. Internally converted to seconds. Default is 'auto'.
- enable_logging (bool, optional): Whether to enable logging or not. Default is False.
Raises:
- ValueError:
- If the
quota_timeorgap_timeformat is invalid. This occurs when the time strings are not formatted correctly (e.g., not containing valid time units like 's', 'm', 'h', 'd'). - If the
quota_timeis less than or equal to zero. A quota time must be a positive value in seconds. - If the
gap_timeis greater than or equal to thequota_time. The gap time should be smaller than the quota time to make sense.
- If the
- TypeError:
- If a non-string value is provided for
quota_timeorgap_time. Bothquota_timeandgap_timemust be strings to be processed.
- If a non-string value is provided for
- AttributeError:
- If an attempt is made to access properties or methods without proper initialization of internal values (such as accessing
execution_timesbefore an operation).
- If an attempt is made to access properties or methods without proper initialization of internal values (such as accessing
Properties:
- start_time: The timestamp when the
Quotainstance is initialized (in seconds fromdefault_timer). - quota_time: Total session quota time in seconds, converted from the input string (e.g., '1h' → 3600).
- auto_gap_time: Flag to indicate whether gap time is set to 'auto', allowing dynamic adjustment.
- gap_time: The buffer time before the quota ends. Can be statically set (manual time in seconds) or dynamically adjusted if 'auto'.
- enable_logging: Whether to log the remaining time to the console.
- execution_times: List of execution times (in seconds) for each loop iteration, used to calculate average execution time.
- total_execution_time: The sum of all execution times, used for calculating the dynamic gap time.
- last_execution_time: Timestamp of the last completed loop iteration (in seconds).
134 def hastime(self): 135 """ 136 Checks if the session still has time before the gap time is reached. 137 138 Returns: 139 ------- 140 bool: True if there is enough time left in the session, False otherwise. 141 """ 142 self._update_gap_time() # Update gap time based on execution history 143 elapsed_time = self._remaining_time() 144 return elapsed_time >= self.gap_time
Checks if the session still has time before the gap time is reached.
Returns:
bool: True if there is enough time left in the session, False otherwise.
146 def time_up(self): 147 """ 148 Checks if the session has reached or exceeded the quota time. 149 150 Returns: 151 ------- 152 bool: True if the quota time has been exceeded, False otherwise. 153 """ 154 self._update_gap_time() # Update gap time based on execution history 155 remained_time = self._remaining_time() 156 return remained_time < self.gap_time
Checks if the session has reached or exceeded the quota time.
Returns:
bool: True if the quota time has been exceeded, False otherwise.
158 def remaining_time(self): 159 """ 160 Returns the remaining time in a human-readable format. 161 162 Returns: 163 ------- 164 str: Remaining time formatted as "xh:xm:xs". 165 """ 166 return self._format_time(self._remaining_time())
Returns the remaining time in a human-readable format.
Returns:
str: Remaining time formatted as "xh:xm:xs".
168 def log_remaining_time(self): 169 """ 170 Logs the remaining time to the console if logging is enabled. 171 172 Logs: 173 ---- 174 str: Remaining time message if logging is enabled. 175 """ 176 if self.enable_logging: 177 logging.info("Remaining time before quota is reached: {}".format(self.remaining_time()))
Logs the remaining time to the console if logging is enabled.
Logs:
str: Remaining time message if logging is enabled.