tools/lib: format code (#31454)

easier to read. pylint used to catch all this stuff, but it's mostly missing in ruff :'(
old-commit-hash: 0846175f44
chrysler-long2
Shane Smiskol 1 year ago committed by GitHub
parent 1f67acfed9
commit 4c7ad7f3b7
  1. 4
      tools/lib/filereader.py
  2. 1
      tools/lib/helpers.py
  3. 20
      tools/lib/logreader.py
  4. 16
      tools/lib/route.py
  5. 2
      tools/lib/tests/test_logreader.py

@ -6,6 +6,7 @@ from openpilot.tools.lib.url_file import URLFile
DATA_ENDPOINT = os.getenv("DATA_ENDPOINT", "http://data-raw.comma.internal/") DATA_ENDPOINT = os.getenv("DATA_ENDPOINT", "http://data-raw.comma.internal/")
def internal_source_available(): def internal_source_available():
try: try:
hostname = urlparse(DATA_ENDPOINT).hostname hostname = urlparse(DATA_ENDPOINT).hostname
@ -16,17 +17,20 @@ def internal_source_available():
pass pass
return False return False
def resolve_name(fn): def resolve_name(fn):
if fn.startswith("cd:/"): if fn.startswith("cd:/"):
return fn.replace("cd:/", DATA_ENDPOINT) return fn.replace("cd:/", DATA_ENDPOINT)
return fn return fn
def file_exists(fn): def file_exists(fn):
fn = resolve_name(fn) fn = resolve_name(fn)
if fn.startswith(("http://", "https://")): if fn.startswith(("http://", "https://")):
return URLFile(fn).get_length_online() != -1 return URLFile(fn).get_length_online() != -1
return os.path.exists(fn) return os.path.exists(fn)
def FileReader(fn, debug=False): def FileReader(fn, debug=False):
fn = resolve_name(fn) fn = resolve_name(fn)
if fn.startswith(("http://", "https://")): if fn.startswith(("http://", "https://")):

@ -3,6 +3,7 @@ import datetime
TIME_FMT = "%Y-%m-%d--%H-%M-%S" TIME_FMT = "%Y-%m-%d--%H-%M-%S"
# regex patterns # regex patterns
class RE: class RE:
DONGLE_ID = r'(?P<dongle_id>[a-f0-9]{16})' DONGLE_ID = r'(?P<dongle_id>[a-f0-9]{16})'

@ -78,6 +78,7 @@ class ReadMode(enum.StrEnum):
AUTO = "a" # default to rlogs, fallback to qlogs AUTO = "a" # default to rlogs, fallback to qlogs
AUTO_INTERACIVE = "i" # default to rlogs, fallback to qlogs with a prompt from the user AUTO_INTERACIVE = "i" # default to rlogs, fallback to qlogs with a prompt from the user
def create_slice_from_string(s: str): def create_slice_from_string(s: str):
m = re.fullmatch(RE.SLICE, s) m = re.fullmatch(RE.SLICE, s)
assert m is not None, f"Invalid slice: {s}" assert m is not None, f"Invalid slice: {s}"
@ -90,9 +91,11 @@ def create_slice_from_string(s: str):
return start return start
return slice(start, end, step) return slice(start, end, step)
def default_valid_file(fn): def default_valid_file(fn):
return fn is not None and file_exists(fn) return fn is not None and file_exists(fn)
def auto_strategy(rlog_paths, qlog_paths, interactive, valid_file): def auto_strategy(rlog_paths, qlog_paths, interactive, valid_file):
# auto select logs based on availability # auto select logs based on availability
if any(rlog is None or not valid_file(rlog) for rlog in rlog_paths): if any(rlog is None or not valid_file(rlog) for rlog in rlog_paths):
@ -106,6 +109,7 @@ def auto_strategy(rlog_paths, qlog_paths, interactive, valid_file):
for (rlog, qlog) in zip(rlog_paths, qlog_paths, strict=True)] for (rlog, qlog) in zip(rlog_paths, qlog_paths, strict=True)]
return rlog_paths return rlog_paths
def apply_strategy(mode: ReadMode, rlog_paths, qlog_paths, valid_file=default_valid_file): def apply_strategy(mode: ReadMode, rlog_paths, qlog_paths, valid_file=default_valid_file):
if mode == ReadMode.RLOG: if mode == ReadMode.RLOG:
return rlog_paths return rlog_paths
@ -116,11 +120,12 @@ def apply_strategy(mode: ReadMode, rlog_paths, qlog_paths, valid_file=default_va
elif mode == ReadMode.AUTO_INTERACIVE: elif mode == ReadMode.AUTO_INTERACIVE:
return auto_strategy(rlog_paths, qlog_paths, True, valid_file) return auto_strategy(rlog_paths, qlog_paths, True, valid_file)
def parse_slice(sr: SegmentRange): def parse_slice(sr: SegmentRange):
s = create_slice_from_string(sr._slice) s = create_slice_from_string(sr._slice)
if isinstance(s, slice): if isinstance(s, slice):
if s.stop is None or s.stop < 0 or (s.start is not None and s.start < 0): # we need the number of segments in order to parse this slice if s.stop is None or s.stop < 0 or (s.start is not None and s.start < 0): # we need the number of segments in order to parse this slice
segs = np.arange(sr.get_max_seg_number()+1) segs = np.arange(sr.get_max_seg_number() + 1)
else: else:
segs = np.arange(s.stop + 1) segs = np.arange(s.stop + 1)
return segs[s] return segs[s]
@ -129,6 +134,7 @@ def parse_slice(sr: SegmentRange):
s = sr.get_max_seg_number() + s + 1 s = sr.get_max_seg_number() + s + 1
return [s] return [s]
def comma_api_source(sr: SegmentRange, mode: ReadMode): def comma_api_source(sr: SegmentRange, mode: ReadMode):
segs = parse_slice(sr) segs = parse_slice(sr)
@ -143,6 +149,7 @@ def comma_api_source(sr: SegmentRange, mode: ReadMode):
return apply_strategy(mode, rlog_paths, qlog_paths, valid_file=valid_file) return apply_strategy(mode, rlog_paths, qlog_paths, valid_file=valid_file)
def internal_source(sr: SegmentRange, mode: ReadMode): def internal_source(sr: SegmentRange, mode: ReadMode):
if not internal_source_available(): if not internal_source_available():
raise Exception("Internal source not available") raise Exception("Internal source not available")
@ -157,6 +164,7 @@ def internal_source(sr: SegmentRange, mode: ReadMode):
return apply_strategy(mode, rlog_paths, qlog_paths) return apply_strategy(mode, rlog_paths, qlog_paths)
def openpilotci_source(sr: SegmentRange, mode: ReadMode): def openpilotci_source(sr: SegmentRange, mode: ReadMode):
segs = parse_slice(sr) segs = parse_slice(sr)
@ -165,19 +173,23 @@ def openpilotci_source(sr: SegmentRange, mode: ReadMode):
return apply_strategy(mode, rlog_paths, qlog_paths) return apply_strategy(mode, rlog_paths, qlog_paths)
def comma_car_segments_source(sr: SegmentRange, mode=ReadMode.RLOG): def comma_car_segments_source(sr: SegmentRange, mode=ReadMode.RLOG):
segs = parse_slice(sr) segs = parse_slice(sr)
return [get_comma_segments_url(sr.route_name, seg) for seg in segs] return [get_comma_segments_url(sr.route_name, seg) for seg in segs]
def direct_source(file_or_url): def direct_source(file_or_url):
return [file_or_url] return [file_or_url]
def get_invalid_files(files): def get_invalid_files(files):
for f in files: for f in files:
if f is None or not file_exists(f): if f is None or not file_exists(f):
yield f yield f
def check_source(source, *args): def check_source(source, *args):
try: try:
files = source(*args) files = source(*args)
@ -186,6 +198,7 @@ def check_source(source, *args):
except Exception as e: except Exception as e:
return e, None return e, None
def auto_source(sr: SegmentRange, mode=ReadMode.RLOG): def auto_source(sr: SegmentRange, mode=ReadMode.RLOG):
if mode == ReadMode.SANITIZED: if mode == ReadMode.SANITIZED:
return comma_car_segments_source(sr, mode) return comma_car_segments_source(sr, mode)
@ -201,23 +214,27 @@ def auto_source(sr: SegmentRange, mode=ReadMode.RLOG):
raise Exception(f"auto_source could not find any valid source, exceptions for sources: {exceptions}") raise Exception(f"auto_source could not find any valid source, exceptions for sources: {exceptions}")
def parse_useradmin(identifier): def parse_useradmin(identifier):
if "useradmin.comma.ai" in identifier: if "useradmin.comma.ai" in identifier:
query = parse_qs(urlparse(identifier).query) query = parse_qs(urlparse(identifier).query)
return query["onebox"][0] return query["onebox"][0]
return None return None
def parse_cabana(identifier): def parse_cabana(identifier):
if "cabana.comma.ai" in identifier: if "cabana.comma.ai" in identifier:
query = parse_qs(urlparse(identifier).query) query = parse_qs(urlparse(identifier).query)
return query["route"][0] return query["route"][0]
return None return None
def parse_direct(identifier): def parse_direct(identifier):
if identifier.startswith(("http://", "https://", "cd:/")) or pathlib.Path(identifier).exists(): if identifier.startswith(("http://", "https://", "cd:/")) or pathlib.Path(identifier).exists():
return identifier return identifier
return None return None
def parse_indirect(identifier): def parse_indirect(identifier):
parsed = parse_useradmin(identifier) or parse_cabana(identifier) parsed = parse_useradmin(identifier) or parse_cabana(identifier)
@ -295,6 +312,7 @@ are uploaded or auto fallback to qlogs with '/a' selector at the end of the rout
if __name__ == "__main__": if __name__ == "__main__":
import codecs import codecs
# capnproto <= 0.8.0 throws errors converting byte data to string # capnproto <= 0.8.0 throws errors converting byte data to string
# below line catches those errors and replaces the bytes with \x__ # below line catches those errors and replaces the bytes with \x__
codecs.register_error("strict", codecs.backslashreplace_errors) codecs.register_error("strict", codecs.backslashreplace_errors)

@ -17,6 +17,7 @@ CAMERA_FILENAMES = ['fcamera.hevc', 'video.hevc']
DCAMERA_FILENAMES = ['dcamera.hevc'] DCAMERA_FILENAMES = ['dcamera.hevc']
ECAMERA_FILENAMES = ['ecamera.hevc'] ECAMERA_FILENAMES = ['ecamera.hevc']
class Route: class Route:
def __init__(self, name, data_dir=None): def __init__(self, name, data_dir=None):
self._name = RouteName(name) self._name = RouteName(name)
@ -37,27 +38,27 @@ class Route:
def log_paths(self): def log_paths(self):
log_path_by_seg_num = {s.name.segment_num: s.log_path for s in self._segments} log_path_by_seg_num = {s.name.segment_num: s.log_path for s in self._segments}
return [log_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [log_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
def qlog_paths(self): def qlog_paths(self):
qlog_path_by_seg_num = {s.name.segment_num: s.qlog_path for s in self._segments} qlog_path_by_seg_num = {s.name.segment_num: s.qlog_path for s in self._segments}
return [qlog_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [qlog_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
def camera_paths(self): def camera_paths(self):
camera_path_by_seg_num = {s.name.segment_num: s.camera_path for s in self._segments} camera_path_by_seg_num = {s.name.segment_num: s.camera_path for s in self._segments}
return [camera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [camera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
def dcamera_paths(self): def dcamera_paths(self):
dcamera_path_by_seg_num = {s.name.segment_num: s.dcamera_path for s in self._segments} dcamera_path_by_seg_num = {s.name.segment_num: s.dcamera_path for s in self._segments}
return [dcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [dcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
def ecamera_paths(self): def ecamera_paths(self):
ecamera_path_by_seg_num = {s.name.segment_num: s.ecamera_path for s in self._segments} ecamera_path_by_seg_num = {s.name.segment_num: s.ecamera_path for s in self._segments}
return [ecamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [ecamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
def qcamera_paths(self): def qcamera_paths(self):
qcamera_path_by_seg_num = {s.name.segment_num: s.qcamera_path for s in self._segments} qcamera_path_by_seg_num = {s.name.segment_num: s.qcamera_path for s in self._segments}
return [qcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number+1)] return [qcamera_path_by_seg_num.get(i, None) for i in range(self.max_seg_number + 1)]
# TODO: refactor this, it's super repetitive # TODO: refactor this, it's super repetitive
def _get_segments_remote(self): def _get_segments_remote(self):
@ -159,6 +160,7 @@ class Route:
raise ValueError(f'Could not find segments for route {self.name.canonical_name} in data directory {data_dir}') raise ValueError(f'Could not find segments for route {self.name.canonical_name} in data directory {data_dir}')
return sorted(segments, key=lambda seg: seg.name.segment_num) return sorted(segments, key=lambda seg: seg.name.segment_num)
class Segment: class Segment:
def __init__(self, name, log_path, qlog_path, camera_path, dcamera_path, ecamera_path, qcamera_path): def __init__(self, name, log_path, qlog_path, camera_path, dcamera_path, ecamera_path, qcamera_path):
self._name = SegmentName(name) self._name = SegmentName(name)
@ -173,6 +175,7 @@ class Segment:
def name(self): def name(self):
return self._name return self._name
class RouteName: class RouteName:
def __init__(self, name_str: str): def __init__(self, name_str: str):
self._name_str = name_str self._name_str = name_str
@ -194,6 +197,7 @@ class RouteName:
def __str__(self) -> str: return self._canonical_name def __str__(self) -> str: return self._canonical_name
class SegmentName: class SegmentName:
# TODO: add constructor that takes dongle_id, time_str, segment_num and then create instances # TODO: add constructor that takes dongle_id, time_str, segment_num and then create instances
# of this class instead of manually constructing a segment name (use canonical_name prop instead) # of this class instead of manually constructing a segment name (use canonical_name prop instead)

@ -110,7 +110,7 @@ class TestLogReader(unittest.TestCase):
qlog_len = len(list(LogReader(f"{TEST_ROUTE}/0/q"))) qlog_len = len(list(LogReader(f"{TEST_ROUTE}/0/q")))
qlog_len_2 = len(list(LogReader([f"{TEST_ROUTE}/0/q", f"{TEST_ROUTE}/0/q"]))) qlog_len_2 = len(list(LogReader([f"{TEST_ROUTE}/0/q", f"{TEST_ROUTE}/0/q"])))
self.assertEqual(qlog_len*2, qlog_len_2) self.assertEqual(qlog_len * 2, qlog_len_2)
@pytest.mark.slow @pytest.mark.slow
@mock.patch("openpilot.tools.lib.logreader._LogFileReader") @mock.patch("openpilot.tools.lib.logreader._LogFileReader")

Loading…
Cancel
Save