vimgolf_gym.log_parser
Log parser for VimGolf executor
1""" 2Log parser for VimGolf executor 3""" 4 5import copy 6import json 7import os 8from abc import ABC, abstractmethod 9from typing import Type 10 11from vimgolf_gym.dataclasses import VimGolfEnvResult 12 13 14class AbstractLogParser(ABC): 15 def __init__(self): ... 16 @abstractmethod 17 def feed_line(self, line: str): ... 18 19 20# We keep track of the log file attributes. 21# Specifically, the file size. 22# If the file size changes, we will reparse the log. 23# In more advanced usage, we could seek to given point and parse from there, avoiding reparsing from the beginning. 24class LogWatcher: 25 def __init__(self, log_file: str, parser_class: Type[AbstractLogParser]): 26 """ 27 Initialize the log watcher with a log file and a parser class. 28 29 Args: 30 log_file (str): The path to the log file. 31 parser_class (Type[AbstractLogParser]): A class that implements the AbstractLogParser interface. 32 33 Attributes: 34 log_file (str): The path to the log file. 35 parser_class (Type[AbstractLogParser]): The class of the parser. 36 parser (AbstractLogParser): An instance of the parser class. 37 last_filesize (int): The size of the log file when it was last checked. 38 last_position (int): The last read position in the log file. 39 """ 40 self.log_file = log_file 41 self.parser_class = parser_class 42 self.parser = parser_class() 43 self.last_filesize = 0 44 self.last_position = 0 # Track the last read position 45 46 def update(self, style="advanced"): 47 """ 48 Update the log watcher using one of three strategies. 49 50 The ``advanced`` strategy is the default. It checks the file size 51 and only reads new content if the file size has changed. If the file 52 size is smaller than the last recorded size, it resets the parser and 53 reads the entire file. 54 55 The ``simple`` strategy reads the entire log file every time it is 56 called. This is simple, but slow for large log files. 57 58 The ``naive`` strategy reads the entire log file every time it is 59 called, but it does not reset the parser. This is faster than the 60 ``simple`` strategy, but it does not handle the case where the log 61 file is truncated. 62 63 Args: 64 style (str, optional): The update strategy to use. Must be one of 65 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 66 """ 67 if style == "advanced": 68 self.advanced_update() 69 elif style == "simple": 70 self.simple_update() 71 elif style == "naive": 72 self.naive_update() 73 else: 74 raise ValueError( 75 "Unrecognized update option: %s (should be in advanced, simple, naive)" 76 % style 77 ) 78 79 def simple_update(self): 80 """ 81 Read the entire log file and reset the parser if the file size has changed. 82 83 The ``simple`` strategy reads the entire log file every time it is 84 called. This is simple, but slow for large log files. 85 """ 86 current_size = ( 87 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 88 ) 89 if current_size != self.last_filesize: 90 self.naive_update() 91 self.last_filesize = current_size 92 93 def naive_update(self): 94 """ 95 Reset the parser and read the entire log file. 96 97 This is slow for large log files, but it is simple and handles 98 the case where the log file is truncated. 99 100 """ 101 self.parser = self.parser_class() 102 if os.path.exists(self.log_file): 103 with open(self.log_file, "r") as f: 104 for line in f.readlines(): 105 self.parser.feed_line(line) 106 self.last_filesize = ( 107 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 108 ) 109 self.last_position = self.last_filesize 110 111 def advanced_update(self): 112 """ 113 Read only the new content from the log file. 114 115 The ``advanced`` strategy reads only the new content from the log file, 116 starting from the last recorded position. This is fast for large log 117 files, but it requires keeping track of the last recorded position. 118 119 If the file size has decreased, it resets the parser and reads the 120 entire file. 121 """ 122 if not os.path.exists(self.log_file): 123 return 124 125 current_size = os.path.getsize(self.log_file) 126 127 # If file size decreased (file was truncated), do a full reset 128 if current_size < self.last_filesize: 129 self.naive_update() 130 return 131 132 # If file size increased, read only the new content 133 if current_size > self.last_filesize: 134 with open(self.log_file, "r") as f: 135 f.seek(self.last_position) 136 while True: 137 line = f.readline() 138 if not line: # End of file 139 break 140 self.parser.feed_line(line) 141 142 # Update tracking variables 143 self.last_filesize = current_size 144 self.last_position = f.tell() 145 146 147class VimGolfLogWatcher(LogWatcher): 148 def __init__(self, log_file: str, update_style="advanced"): 149 """ 150 Initialize a VimGolfLogWatcher with a log file and an update style. 151 152 The VimGolfLogWatcher is a LogWatcher that is specialized for 153 reading VimGolf logs. 154 155 Args: 156 log_file (str): The path to the log file. 157 update_style (str, optional): The update strategy to use. Must be one of 158 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 159 160 Returns: 161 [return_type]: [description of return value] 162 """ 163 super().__init__(log_file=log_file, parser_class=VimGolfLogParser) 164 self.parser: VimGolfLogParser 165 self.update_style = update_style 166 167 def default_update(self): 168 """ 169 Call the update method with the default update style. 170 171 This method is a convenience wrapper around the update method, 172 calling it with the default update style specified in the 173 constructor. 174 175 See the update method for more details. 176 """ 177 self.update(style=self.update_style) 178 179 @property 180 def success(self): 181 """ 182 Check if the vimgolf challenge has been solved successfully. 183 184 This property checks if the vimgolf challenge has been solved 185 successfully. It updates the log watcher if necessary before 186 checking the success status. 187 188 Returns: 189 bool: True if the challenge has been solved successfully, False otherwise. 190 """ 191 self.default_update() 192 return self.parser.success 193 194 def get_best_success_result(self): 195 """ 196 Return the best success result in the log watcher. 197 198 This method returns the best success result in the log watcher, 199 updating the log watcher if necessary before returning the result. 200 201 Returns: 202 VimGolfEnvResult: The best success result in the log watcher, or None if 203 there is no success result. 204 """ 205 self.default_update() 206 return self.parser.get_best_success_result() 207 208 def get_last_success_result(self): 209 """ 210 Return the last success result in the log watcher. 211 212 This method returns the last success result in the log watcher, 213 updating the log watcher if necessary before returning the result. 214 215 Returns: 216 VimGolfEnvResult: The last success result in the log watcher, or None if 217 there is no success result. 218 """ 219 self.default_update() 220 return self.parser.get_last_success_result() 221 222 @property 223 def results(self): 224 """ 225 The results of the vimgolf challenge environment. 226 227 This property returns the results of the vimgolf challenge environment, 228 updating the log watcher if necessary before returning the results. 229 230 Returns: 231 list[VimGolfEnvResult]: The results of the vimgolf challenge environment, or an empty list if 232 there are no results. 233 """ 234 self.default_update() 235 return self.parser.results 236 237 @property 238 def success_results(self): 239 """ 240 The successful results of the vimgolf challenge environment. 241 242 This property returns the successful results of the vimgolf challenge 243 environment, updating the log watcher if necessary before returning the 244 results. 245 246 Returns: 247 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 248 empty list if there are no successful results. 249 """ 250 self.default_update() 251 return self.parser.success_results 252 253 254class VimGolfLogParser(AbstractLogParser): 255 def __init__(self): 256 """ 257 Initialize the VimGolfLogParser. 258 259 The VimGolfLogParser is initialized with an empty list of results. 260 """ 261 self.results: list[VimGolfEnvResult] = [] 262 263 def feed_line(self, line: str): 264 """ 265 Feed a line to the parser. 266 267 The line should be a JSON-formatted string. The parser will attempt to 268 parse the line as a JSON object, and if it is a dictionary, it will 269 check if the dictionary has an "event_type" key with value 270 "vimgolf_result". If so, it will attempt to parse the value of the 271 "event_data" key as a VimGolfEnvResult object and append it to the 272 results list. 273 274 If the line is not a valid JSON object, or if the JSON object does not 275 have the correct structure, the line will be ignored. 276 277 Args: 278 line (str): The line of text to feed to the parser. 279 """ 280 try: 281 data = json.loads(line.strip()) 282 if type(data) == dict: 283 if data.get("event_type", None) == "vimgolf_result": 284 event_data = data.get("event_data", None) 285 if type(event_data) == dict: 286 parsed_result = VimGolfEnvResult.parse_obj(event_data) 287 self.results.append(parsed_result) 288 except json.JSONDecodeError: 289 ... 290 291 @property 292 def success_results(self): 293 """ 294 The successful results of the vimgolf challenge environment. 295 296 This property returns the successful results of the vimgolf challenge 297 environment, which are the results in the results list where the 298 correct attribute is True. 299 300 Returns: 301 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 302 empty list if there are no successful results. 303 """ 304 return [it for it in self.results if it.correct] 305 306 @property 307 def success(self): 308 """ 309 Check if the vimgolf challenge has been solved successfully. 310 311 This property checks if the vimgolf challenge has been solved 312 successfully. It returns True if there are any successful results in 313 the results list, and False otherwise. 314 315 Returns: 316 bool: True if the challenge has been solved successfully, False otherwise. 317 """ 318 return len(self.success_results) != 0 319 320 def get_last_success_result(self): 321 """ 322 Return the last success result in the log watcher. 323 324 This method returns the last success result in the log watcher, 325 which is the last result in the success_results list. 326 327 Returns: 328 VimGolfEnvResult: The last success result in the log watcher, or None if there is no 329 success result. 330 """ 331 success_results = self.success_results 332 if success_results: 333 return success_results[-1] 334 335 def get_best_success_result(self): 336 """Return the result with the lowest score""" 337 success_results = copy.deepcopy(self.success_results) 338 if success_results: 339 success_results.sort(key=lambda x: x.score) 340 return success_results[0]
15class AbstractLogParser(ABC): 16 def __init__(self): ... 17 @abstractmethod 18 def feed_line(self, line: str): ...
Helper class that provides a standard way to create an ABC using inheritance.
25class LogWatcher: 26 def __init__(self, log_file: str, parser_class: Type[AbstractLogParser]): 27 """ 28 Initialize the log watcher with a log file and a parser class. 29 30 Args: 31 log_file (str): The path to the log file. 32 parser_class (Type[AbstractLogParser]): A class that implements the AbstractLogParser interface. 33 34 Attributes: 35 log_file (str): The path to the log file. 36 parser_class (Type[AbstractLogParser]): The class of the parser. 37 parser (AbstractLogParser): An instance of the parser class. 38 last_filesize (int): The size of the log file when it was last checked. 39 last_position (int): The last read position in the log file. 40 """ 41 self.log_file = log_file 42 self.parser_class = parser_class 43 self.parser = parser_class() 44 self.last_filesize = 0 45 self.last_position = 0 # Track the last read position 46 47 def update(self, style="advanced"): 48 """ 49 Update the log watcher using one of three strategies. 50 51 The ``advanced`` strategy is the default. It checks the file size 52 and only reads new content if the file size has changed. If the file 53 size is smaller than the last recorded size, it resets the parser and 54 reads the entire file. 55 56 The ``simple`` strategy reads the entire log file every time it is 57 called. This is simple, but slow for large log files. 58 59 The ``naive`` strategy reads the entire log file every time it is 60 called, but it does not reset the parser. This is faster than the 61 ``simple`` strategy, but it does not handle the case where the log 62 file is truncated. 63 64 Args: 65 style (str, optional): The update strategy to use. Must be one of 66 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 67 """ 68 if style == "advanced": 69 self.advanced_update() 70 elif style == "simple": 71 self.simple_update() 72 elif style == "naive": 73 self.naive_update() 74 else: 75 raise ValueError( 76 "Unrecognized update option: %s (should be in advanced, simple, naive)" 77 % style 78 ) 79 80 def simple_update(self): 81 """ 82 Read the entire log file and reset the parser if the file size has changed. 83 84 The ``simple`` strategy reads the entire log file every time it is 85 called. This is simple, but slow for large log files. 86 """ 87 current_size = ( 88 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 89 ) 90 if current_size != self.last_filesize: 91 self.naive_update() 92 self.last_filesize = current_size 93 94 def naive_update(self): 95 """ 96 Reset the parser and read the entire log file. 97 98 This is slow for large log files, but it is simple and handles 99 the case where the log file is truncated. 100 101 """ 102 self.parser = self.parser_class() 103 if os.path.exists(self.log_file): 104 with open(self.log_file, "r") as f: 105 for line in f.readlines(): 106 self.parser.feed_line(line) 107 self.last_filesize = ( 108 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 109 ) 110 self.last_position = self.last_filesize 111 112 def advanced_update(self): 113 """ 114 Read only the new content from the log file. 115 116 The ``advanced`` strategy reads only the new content from the log file, 117 starting from the last recorded position. This is fast for large log 118 files, but it requires keeping track of the last recorded position. 119 120 If the file size has decreased, it resets the parser and reads the 121 entire file. 122 """ 123 if not os.path.exists(self.log_file): 124 return 125 126 current_size = os.path.getsize(self.log_file) 127 128 # If file size decreased (file was truncated), do a full reset 129 if current_size < self.last_filesize: 130 self.naive_update() 131 return 132 133 # If file size increased, read only the new content 134 if current_size > self.last_filesize: 135 with open(self.log_file, "r") as f: 136 f.seek(self.last_position) 137 while True: 138 line = f.readline() 139 if not line: # End of file 140 break 141 self.parser.feed_line(line) 142 143 # Update tracking variables 144 self.last_filesize = current_size 145 self.last_position = f.tell()
26 def __init__(self, log_file: str, parser_class: Type[AbstractLogParser]): 27 """ 28 Initialize the log watcher with a log file and a parser class. 29 30 Args: 31 log_file (str): The path to the log file. 32 parser_class (Type[AbstractLogParser]): A class that implements the AbstractLogParser interface. 33 34 Attributes: 35 log_file (str): The path to the log file. 36 parser_class (Type[AbstractLogParser]): The class of the parser. 37 parser (AbstractLogParser): An instance of the parser class. 38 last_filesize (int): The size of the log file when it was last checked. 39 last_position (int): The last read position in the log file. 40 """ 41 self.log_file = log_file 42 self.parser_class = parser_class 43 self.parser = parser_class() 44 self.last_filesize = 0 45 self.last_position = 0 # Track the last read position
Initialize the log watcher with a log file and a parser class.
Arguments:
- log_file (str): The path to the log file.
- parser_class (Type[AbstractLogParser]): A class that implements the AbstractLogParser interface.
Attributes:
- log_file (str): The path to the log file.
- parser_class (Type[AbstractLogParser]): The class of the parser.
- parser (AbstractLogParser): An instance of the parser class.
- last_filesize (int): The size of the log file when it was last checked.
- last_position (int): The last read position in the log file.
47 def update(self, style="advanced"): 48 """ 49 Update the log watcher using one of three strategies. 50 51 The ``advanced`` strategy is the default. It checks the file size 52 and only reads new content if the file size has changed. If the file 53 size is smaller than the last recorded size, it resets the parser and 54 reads the entire file. 55 56 The ``simple`` strategy reads the entire log file every time it is 57 called. This is simple, but slow for large log files. 58 59 The ``naive`` strategy reads the entire log file every time it is 60 called, but it does not reset the parser. This is faster than the 61 ``simple`` strategy, but it does not handle the case where the log 62 file is truncated. 63 64 Args: 65 style (str, optional): The update strategy to use. Must be one of 66 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 67 """ 68 if style == "advanced": 69 self.advanced_update() 70 elif style == "simple": 71 self.simple_update() 72 elif style == "naive": 73 self.naive_update() 74 else: 75 raise ValueError( 76 "Unrecognized update option: %s (should be in advanced, simple, naive)" 77 % style 78 )
Update the log watcher using one of three strategies.
The advanced
strategy is the default. It checks the file size
and only reads new content if the file size has changed. If the file
size is smaller than the last recorded size, it resets the parser and
reads the entire file.
The simple
strategy reads the entire log file every time it is
called. This is simple, but slow for large log files.
The naive
strategy reads the entire log file every time it is
called, but it does not reset the parser. This is faster than the
simple
strategy, but it does not handle the case where the log
file is truncated.
Arguments:
- style (str, optional): The update strategy to use. Must be one of
advanced
,simple
, ornaive
. Defaults toadvanced
.
80 def simple_update(self): 81 """ 82 Read the entire log file and reset the parser if the file size has changed. 83 84 The ``simple`` strategy reads the entire log file every time it is 85 called. This is simple, but slow for large log files. 86 """ 87 current_size = ( 88 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 89 ) 90 if current_size != self.last_filesize: 91 self.naive_update() 92 self.last_filesize = current_size
Read the entire log file and reset the parser if the file size has changed.
The simple
strategy reads the entire log file every time it is
called. This is simple, but slow for large log files.
94 def naive_update(self): 95 """ 96 Reset the parser and read the entire log file. 97 98 This is slow for large log files, but it is simple and handles 99 the case where the log file is truncated. 100 101 """ 102 self.parser = self.parser_class() 103 if os.path.exists(self.log_file): 104 with open(self.log_file, "r") as f: 105 for line in f.readlines(): 106 self.parser.feed_line(line) 107 self.last_filesize = ( 108 os.path.getsize(self.log_file) if os.path.exists(self.log_file) else 0 109 ) 110 self.last_position = self.last_filesize
Reset the parser and read the entire log file.
This is slow for large log files, but it is simple and handles the case where the log file is truncated.
112 def advanced_update(self): 113 """ 114 Read only the new content from the log file. 115 116 The ``advanced`` strategy reads only the new content from the log file, 117 starting from the last recorded position. This is fast for large log 118 files, but it requires keeping track of the last recorded position. 119 120 If the file size has decreased, it resets the parser and reads the 121 entire file. 122 """ 123 if not os.path.exists(self.log_file): 124 return 125 126 current_size = os.path.getsize(self.log_file) 127 128 # If file size decreased (file was truncated), do a full reset 129 if current_size < self.last_filesize: 130 self.naive_update() 131 return 132 133 # If file size increased, read only the new content 134 if current_size > self.last_filesize: 135 with open(self.log_file, "r") as f: 136 f.seek(self.last_position) 137 while True: 138 line = f.readline() 139 if not line: # End of file 140 break 141 self.parser.feed_line(line) 142 143 # Update tracking variables 144 self.last_filesize = current_size 145 self.last_position = f.tell()
Read only the new content from the log file.
The advanced
strategy reads only the new content from the log file,
starting from the last recorded position. This is fast for large log
files, but it requires keeping track of the last recorded position.
If the file size has decreased, it resets the parser and reads the entire file.
148class VimGolfLogWatcher(LogWatcher): 149 def __init__(self, log_file: str, update_style="advanced"): 150 """ 151 Initialize a VimGolfLogWatcher with a log file and an update style. 152 153 The VimGolfLogWatcher is a LogWatcher that is specialized for 154 reading VimGolf logs. 155 156 Args: 157 log_file (str): The path to the log file. 158 update_style (str, optional): The update strategy to use. Must be one of 159 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 160 161 Returns: 162 [return_type]: [description of return value] 163 """ 164 super().__init__(log_file=log_file, parser_class=VimGolfLogParser) 165 self.parser: VimGolfLogParser 166 self.update_style = update_style 167 168 def default_update(self): 169 """ 170 Call the update method with the default update style. 171 172 This method is a convenience wrapper around the update method, 173 calling it with the default update style specified in the 174 constructor. 175 176 See the update method for more details. 177 """ 178 self.update(style=self.update_style) 179 180 @property 181 def success(self): 182 """ 183 Check if the vimgolf challenge has been solved successfully. 184 185 This property checks if the vimgolf challenge has been solved 186 successfully. It updates the log watcher if necessary before 187 checking the success status. 188 189 Returns: 190 bool: True if the challenge has been solved successfully, False otherwise. 191 """ 192 self.default_update() 193 return self.parser.success 194 195 def get_best_success_result(self): 196 """ 197 Return the best success result in the log watcher. 198 199 This method returns the best success result in the log watcher, 200 updating the log watcher if necessary before returning the result. 201 202 Returns: 203 VimGolfEnvResult: The best success result in the log watcher, or None if 204 there is no success result. 205 """ 206 self.default_update() 207 return self.parser.get_best_success_result() 208 209 def get_last_success_result(self): 210 """ 211 Return the last success result in the log watcher. 212 213 This method returns the last success result in the log watcher, 214 updating the log watcher if necessary before returning the result. 215 216 Returns: 217 VimGolfEnvResult: The last success result in the log watcher, or None if 218 there is no success result. 219 """ 220 self.default_update() 221 return self.parser.get_last_success_result() 222 223 @property 224 def results(self): 225 """ 226 The results of the vimgolf challenge environment. 227 228 This property returns the results of the vimgolf challenge environment, 229 updating the log watcher if necessary before returning the results. 230 231 Returns: 232 list[VimGolfEnvResult]: The results of the vimgolf challenge environment, or an empty list if 233 there are no results. 234 """ 235 self.default_update() 236 return self.parser.results 237 238 @property 239 def success_results(self): 240 """ 241 The successful results of the vimgolf challenge environment. 242 243 This property returns the successful results of the vimgolf challenge 244 environment, updating the log watcher if necessary before returning the 245 results. 246 247 Returns: 248 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 249 empty list if there are no successful results. 250 """ 251 self.default_update() 252 return self.parser.success_results
149 def __init__(self, log_file: str, update_style="advanced"): 150 """ 151 Initialize a VimGolfLogWatcher with a log file and an update style. 152 153 The VimGolfLogWatcher is a LogWatcher that is specialized for 154 reading VimGolf logs. 155 156 Args: 157 log_file (str): The path to the log file. 158 update_style (str, optional): The update strategy to use. Must be one of 159 ``advanced``, ``simple``, or ``naive``. Defaults to ``advanced``. 160 161 Returns: 162 [return_type]: [description of return value] 163 """ 164 super().__init__(log_file=log_file, parser_class=VimGolfLogParser) 165 self.parser: VimGolfLogParser 166 self.update_style = update_style
Initialize a VimGolfLogWatcher with a log file and an update style.
The VimGolfLogWatcher is a LogWatcher that is specialized for reading VimGolf logs.
Arguments:
- log_file (str): The path to the log file.
- update_style (str, optional): The update strategy to use. Must be one of
advanced
,simple
, ornaive
. Defaults toadvanced
.
Returns:
[return_type]: [description of return value]
168 def default_update(self): 169 """ 170 Call the update method with the default update style. 171 172 This method is a convenience wrapper around the update method, 173 calling it with the default update style specified in the 174 constructor. 175 176 See the update method for more details. 177 """ 178 self.update(style=self.update_style)
Call the update method with the default update style.
This method is a convenience wrapper around the update method, calling it with the default update style specified in the constructor.
See the update method for more details.
180 @property 181 def success(self): 182 """ 183 Check if the vimgolf challenge has been solved successfully. 184 185 This property checks if the vimgolf challenge has been solved 186 successfully. It updates the log watcher if necessary before 187 checking the success status. 188 189 Returns: 190 bool: True if the challenge has been solved successfully, False otherwise. 191 """ 192 self.default_update() 193 return self.parser.success
Check if the vimgolf challenge has been solved successfully.
This property checks if the vimgolf challenge has been solved successfully. It updates the log watcher if necessary before checking the success status.
Returns:
bool: True if the challenge has been solved successfully, False otherwise.
195 def get_best_success_result(self): 196 """ 197 Return the best success result in the log watcher. 198 199 This method returns the best success result in the log watcher, 200 updating the log watcher if necessary before returning the result. 201 202 Returns: 203 VimGolfEnvResult: The best success result in the log watcher, or None if 204 there is no success result. 205 """ 206 self.default_update() 207 return self.parser.get_best_success_result()
Return the best success result in the log watcher.
This method returns the best success result in the log watcher, updating the log watcher if necessary before returning the result.
Returns:
VimGolfEnvResult: The best success result in the log watcher, or None if there is no success result.
209 def get_last_success_result(self): 210 """ 211 Return the last success result in the log watcher. 212 213 This method returns the last success result in the log watcher, 214 updating the log watcher if necessary before returning the result. 215 216 Returns: 217 VimGolfEnvResult: The last success result in the log watcher, or None if 218 there is no success result. 219 """ 220 self.default_update() 221 return self.parser.get_last_success_result()
Return the last success result in the log watcher.
This method returns the last success result in the log watcher, updating the log watcher if necessary before returning the result.
Returns:
VimGolfEnvResult: The last success result in the log watcher, or None if there is no success result.
223 @property 224 def results(self): 225 """ 226 The results of the vimgolf challenge environment. 227 228 This property returns the results of the vimgolf challenge environment, 229 updating the log watcher if necessary before returning the results. 230 231 Returns: 232 list[VimGolfEnvResult]: The results of the vimgolf challenge environment, or an empty list if 233 there are no results. 234 """ 235 self.default_update() 236 return self.parser.results
The results of the vimgolf challenge environment.
This property returns the results of the vimgolf challenge environment, updating the log watcher if necessary before returning the results.
Returns:
list[VimGolfEnvResult]: The results of the vimgolf challenge environment, or an empty list if there are no results.
238 @property 239 def success_results(self): 240 """ 241 The successful results of the vimgolf challenge environment. 242 243 This property returns the successful results of the vimgolf challenge 244 environment, updating the log watcher if necessary before returning the 245 results. 246 247 Returns: 248 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 249 empty list if there are no successful results. 250 """ 251 self.default_update() 252 return self.parser.success_results
The successful results of the vimgolf challenge environment.
This property returns the successful results of the vimgolf challenge environment, updating the log watcher if necessary before returning the results.
Returns:
list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an empty list if there are no successful results.
Inherited Members
255class VimGolfLogParser(AbstractLogParser): 256 def __init__(self): 257 """ 258 Initialize the VimGolfLogParser. 259 260 The VimGolfLogParser is initialized with an empty list of results. 261 """ 262 self.results: list[VimGolfEnvResult] = [] 263 264 def feed_line(self, line: str): 265 """ 266 Feed a line to the parser. 267 268 The line should be a JSON-formatted string. The parser will attempt to 269 parse the line as a JSON object, and if it is a dictionary, it will 270 check if the dictionary has an "event_type" key with value 271 "vimgolf_result". If so, it will attempt to parse the value of the 272 "event_data" key as a VimGolfEnvResult object and append it to the 273 results list. 274 275 If the line is not a valid JSON object, or if the JSON object does not 276 have the correct structure, the line will be ignored. 277 278 Args: 279 line (str): The line of text to feed to the parser. 280 """ 281 try: 282 data = json.loads(line.strip()) 283 if type(data) == dict: 284 if data.get("event_type", None) == "vimgolf_result": 285 event_data = data.get("event_data", None) 286 if type(event_data) == dict: 287 parsed_result = VimGolfEnvResult.parse_obj(event_data) 288 self.results.append(parsed_result) 289 except json.JSONDecodeError: 290 ... 291 292 @property 293 def success_results(self): 294 """ 295 The successful results of the vimgolf challenge environment. 296 297 This property returns the successful results of the vimgolf challenge 298 environment, which are the results in the results list where the 299 correct attribute is True. 300 301 Returns: 302 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 303 empty list if there are no successful results. 304 """ 305 return [it for it in self.results if it.correct] 306 307 @property 308 def success(self): 309 """ 310 Check if the vimgolf challenge has been solved successfully. 311 312 This property checks if the vimgolf challenge has been solved 313 successfully. It returns True if there are any successful results in 314 the results list, and False otherwise. 315 316 Returns: 317 bool: True if the challenge has been solved successfully, False otherwise. 318 """ 319 return len(self.success_results) != 0 320 321 def get_last_success_result(self): 322 """ 323 Return the last success result in the log watcher. 324 325 This method returns the last success result in the log watcher, 326 which is the last result in the success_results list. 327 328 Returns: 329 VimGolfEnvResult: The last success result in the log watcher, or None if there is no 330 success result. 331 """ 332 success_results = self.success_results 333 if success_results: 334 return success_results[-1] 335 336 def get_best_success_result(self): 337 """Return the result with the lowest score""" 338 success_results = copy.deepcopy(self.success_results) 339 if success_results: 340 success_results.sort(key=lambda x: x.score) 341 return success_results[0]
Helper class that provides a standard way to create an ABC using inheritance.
256 def __init__(self): 257 """ 258 Initialize the VimGolfLogParser. 259 260 The VimGolfLogParser is initialized with an empty list of results. 261 """ 262 self.results: list[VimGolfEnvResult] = []
Initialize the VimGolfLogParser.
The VimGolfLogParser is initialized with an empty list of results.
264 def feed_line(self, line: str): 265 """ 266 Feed a line to the parser. 267 268 The line should be a JSON-formatted string. The parser will attempt to 269 parse the line as a JSON object, and if it is a dictionary, it will 270 check if the dictionary has an "event_type" key with value 271 "vimgolf_result". If so, it will attempt to parse the value of the 272 "event_data" key as a VimGolfEnvResult object and append it to the 273 results list. 274 275 If the line is not a valid JSON object, or if the JSON object does not 276 have the correct structure, the line will be ignored. 277 278 Args: 279 line (str): The line of text to feed to the parser. 280 """ 281 try: 282 data = json.loads(line.strip()) 283 if type(data) == dict: 284 if data.get("event_type", None) == "vimgolf_result": 285 event_data = data.get("event_data", None) 286 if type(event_data) == dict: 287 parsed_result = VimGolfEnvResult.parse_obj(event_data) 288 self.results.append(parsed_result) 289 except json.JSONDecodeError: 290 ...
Feed a line to the parser.
The line should be a JSON-formatted string. The parser will attempt to parse the line as a JSON object, and if it is a dictionary, it will check if the dictionary has an "event_type" key with value "vimgolf_result". If so, it will attempt to parse the value of the "event_data" key as a VimGolfEnvResult object and append it to the results list.
If the line is not a valid JSON object, or if the JSON object does not have the correct structure, the line will be ignored.
Arguments:
- line (str): The line of text to feed to the parser.
292 @property 293 def success_results(self): 294 """ 295 The successful results of the vimgolf challenge environment. 296 297 This property returns the successful results of the vimgolf challenge 298 environment, which are the results in the results list where the 299 correct attribute is True. 300 301 Returns: 302 list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an 303 empty list if there are no successful results. 304 """ 305 return [it for it in self.results if it.correct]
The successful results of the vimgolf challenge environment.
This property returns the successful results of the vimgolf challenge environment, which are the results in the results list where the correct attribute is True.
Returns:
list[VimGolfEnvResult]: The successful results of the vimgolf challenge environment, or an empty list if there are no successful results.
307 @property 308 def success(self): 309 """ 310 Check if the vimgolf challenge has been solved successfully. 311 312 This property checks if the vimgolf challenge has been solved 313 successfully. It returns True if there are any successful results in 314 the results list, and False otherwise. 315 316 Returns: 317 bool: True if the challenge has been solved successfully, False otherwise. 318 """ 319 return len(self.success_results) != 0
Check if the vimgolf challenge has been solved successfully.
This property checks if the vimgolf challenge has been solved successfully. It returns True if there are any successful results in the results list, and False otherwise.
Returns:
bool: True if the challenge has been solved successfully, False otherwise.
321 def get_last_success_result(self): 322 """ 323 Return the last success result in the log watcher. 324 325 This method returns the last success result in the log watcher, 326 which is the last result in the success_results list. 327 328 Returns: 329 VimGolfEnvResult: The last success result in the log watcher, or None if there is no 330 success result. 331 """ 332 success_results = self.success_results 333 if success_results: 334 return success_results[-1]
Return the last success result in the log watcher.
This method returns the last success result in the log watcher, which is the last result in the success_results list.
Returns:
VimGolfEnvResult: The last success result in the log watcher, or None if there is no success result.
336 def get_best_success_result(self): 337 """Return the result with the lowest score""" 338 success_results = copy.deepcopy(self.success_results) 339 if success_results: 340 success_results.sort(key=lambda x: x.score) 341 return success_results[0]
Return the result with the lowest score