def get_lcmtype_dictionary(root_path: str) -> Dict[bytes, Type]: """ Searches recursively from `root_path` for any lcm type definitions and imports as python classes. Returns a dictionary of lcm type classes keyed by the type's fingerprint """ # Search the given root path for lcm types lcmtypes_list = __find_lcmtypes(root_path) log.log(f"Found {len(lcmtypes_list)} lcm types") log.log("Importing lcm types") # Import each lcm type file as a python class & store keyed by fingerprint lcmtypes: Dict[bytes, Type] = {} for module_name in lcmtypes_list: log.if_verbose(f"Importing {module_name}", end="\t") try: # Import the lcm type file & get a reference to the module __import__(module_name) module = sys.modules[module_name] # Pick out the lcm type class from the module class_name = module_name.split(".")[-1] class_reference = getattr(module, class_name) # Store the class by its fingerprint fingerprint = class_reference._get_packed_fingerprint() lcmtypes[fingerprint] = class_reference log.if_verbose(f"-> {hexlify(fingerprint)}") except Exception as error: log.error(f"Error importing {module_name}") raise error return lcmtypes
def parse_lcm_log(file: str, lcm_types: Dict) -> Dict: log.log(f"Parsing lcm log file {file}") # Open log as an LCM EventLog object lcm_log = EventLog(file, "r") first_timestamp = None events: Dict[str, Dict[str, List]] = { } # {CHANNEL: {FIELD1: [values], FIELD2: [values]}} missing_channels = [] for event in lcm_log: assert isinstance(event, Event) # Record the time of the first event as start time if not first_timestamp: first_timestamp = event.timestamp # todo - ignored channels log.if_verbose(f"Event on channel: {event.channel}", end="\t") # Match the message to an lcm type fingerprint = event.data[:8] lcm_type = lcm_types.get(fingerprint, None) if not lcm_type: if event.channel not in missing_channels: missing_channels.append(event.channel) log.error( f"Unable to find lcm type for events on channel {event.channel}" ) continue log.if_verbose(f"-> {lcm_type.__name__}") # Decode the message into a python object try: message = lcm_type.decode(event.data) except: log.error(f"Error decoding event on channel {event.channel}") continue # Convert the message into loggable form & store message_dict = convert_to_primitive(message, event.timestamp - first_timestamp) # Convert to list of values for each field for field in message_dict.keys(): events.setdefault(event.channel, {}).setdefault(field, []).append(message_dict[field]) return events
def __find_lcmtypes(root_path: str) -> List[str]: """ Searches recursively from `root_path` for lcm types. Finds all python files matching the above regex of valid matlab names, imports their details using pyclbr and keeps a record of any which contain functions usually associated with lcm types. Returns a list of files containing lcm types as python modules to be imported e.g. root_path/dir/some_type.py -> dir.some_type """ log.log(f"Searching for lcm types in root directory {root_path}") found_lcmtypes: List[str] = [] for root, dirs, files in os.walk(root_path): log.if_verbose("Searching directory {}".format(root)) # The python package will be the relative path to the file python_package = os.path.relpath(root, root_path).replace(os.sep, ".") if python_package == ".": python_package = "" for file in files: # Ensure file name (and hence lcm-type name) is importable to matlab if not filename_validator.fullmatch(file): continue log.if_verbose(f"Testing file: {file}", end=" ") lcmtype_name = file[:-3] module_name = f"{python_package}.{lcmtype_name}".strip(".") log.if_verbose(f"-> {module_name}") # Load python class from type definition & check validity as lcm type # To be valid, must have `_get_packed_fingerprint` and `decode` methods try: klass = pyclbr.readmodule(module_name)[lcmtype_name] if "decode" in klass.methods and "_get_packed_fingerprint" in klass.methods: found_lcmtypes.append(module_name) log.if_verbose( f"Found lcm definition {klass.name} in file: {file}") except (ImportError, KeyError): continue # Raise error if no lcm type definitions found (nothing will be decoded) if not found_lcmtypes: raise FileNotFoundError("No lcm type definitions found") return found_lcmtypes
def dump_to_pickle(data: Dict, output_file: str): log.log(f"Writing .pkl file to {output_file}.pkl") with open(output_file + ".pkl", "wb") as file: pickle.dump(data, file, protocol=2)
def dump_to_matlab(data: Dict, output_file: str): """ Creates a Matlab .mat file from teh given dictionary """ log.log(f"Writing .mat file to {output_file}.mat") scipy.io.matlab.mio.savemat(output_file + ".mat", data, oned_as='column')