(identifier: str, sources: list[Source], default_mode: ReadMode)
| 148 | |
| 149 | # TODO this should apply to camera files as well |
| 150 | def auto_source(identifier: str, sources: list[Source], default_mode: ReadMode) -> list[str]: |
| 151 | exceptions = {} |
| 152 | |
| 153 | sr = SegmentRange(identifier) |
| 154 | needed_seg_idxs = sr.seg_idxs |
| 155 | |
| 156 | mode = default_mode if sr.selector is None else ReadMode(sr.selector) |
| 157 | if mode == ReadMode.QLOG: |
| 158 | try_fns = [FileName.QLOG] |
| 159 | else: |
| 160 | try_fns = [FileName.RLOG] |
| 161 | |
| 162 | # If selector allows it, fallback to qlogs |
| 163 | if mode in (ReadMode.AUTO, ReadMode.AUTO_INTERACTIVE): |
| 164 | try_fns.append(FileName.QLOG) |
| 165 | |
| 166 | # Build a dict of valid files as we evaluate each source. May contain mix of rlogs, qlogs, and None. |
| 167 | # This function only returns when we've sourced all files, or throws an exception |
| 168 | valid_files: dict[int, str] = {} |
| 169 | for fn in try_fns: |
| 170 | for source in sources: |
| 171 | try: |
| 172 | files = source(sr, needed_seg_idxs, fn) |
| 173 | |
| 174 | # Build a dict of valid files |
| 175 | valid_files |= files |
| 176 | |
| 177 | # Don't check for segment files that have already been found |
| 178 | needed_seg_idxs = [idx for idx in needed_seg_idxs if idx not in valid_files] |
| 179 | |
| 180 | # We've found all files, return them |
| 181 | if len(needed_seg_idxs) == 0: |
| 182 | return list(valid_files.values()) |
| 183 | else: |
| 184 | raise FileNotFoundError(f"Did not find {fn} for seg idxs {needed_seg_idxs} of {sr.route_name}") |
| 185 | |
| 186 | except Exception as e: |
| 187 | exceptions[source.__name__] = e |
| 188 | |
| 189 | if fn == try_fns[0]: |
| 190 | missing_logs = len(needed_seg_idxs) |
| 191 | if mode == ReadMode.AUTO: |
| 192 | cloudlog.warning(f"{missing_logs}/{len(sr.seg_idxs)} rlogs were not found, falling back to qlogs for those segments...") |
| 193 | elif mode == ReadMode.AUTO_INTERACTIVE: |
| 194 | if input(f"{missing_logs}/{len(sr.seg_idxs)} rlogs were not found, would you like to fallback to qlogs for those segments? (y/N) ").lower() != "y": |
| 195 | break |
| 196 | |
| 197 | missing_logs = len(needed_seg_idxs) |
| 198 | raise LogsUnavailable(f"{missing_logs}/{len(sr.seg_idxs)} logs were not found, please ensure all logs " + |
| 199 | "are uploaded. You can fall back to qlogs with '/a' selector at the end of the route name.\n\n" + |
| 200 | "Exceptions for sources:\n - " + "\n - ".join([f"{k}: {repr(v)}" for k, v in exceptions.items()])) |
| 201 | |
| 202 | |
| 203 | def parse_indirect(identifier: str) -> str: |
no test coverage detected