diff --git a/telemetry/gui.py b/telemetry/gui.py index 44eb545..a6aae7b 100644 --- a/telemetry/gui.py +++ b/telemetry/gui.py @@ -196,9 +196,11 @@ class _App: self._log_queue.put(None) def _on_rename(self) -> None: - d = filedialog.askdirectory(title='Select folder to rename', initialdir=_RACES_DIR) + init = self._last_dir.get('rename', os.path.expanduser('~')) + d = filedialog.askdirectory(title='Select folder with CSV files', initialdir=init) if not d: return + self._last_dir['rename'] = d self._set_busy(True) threading.Thread(target=self._worker_rename, args=(d,), daemon=True).start() @@ -209,7 +211,8 @@ class _App: self._push('No CSV files found') for r in results: if r.status == 'renamed': - self._push(f'renamed: {r.old} -> {r.new}') + new_display = os.path.relpath(r.new, _RACES_DIR) if r.new and r.new.startswith(_RACES_DIR) else r.new + self._push(f'renamed: {r.old} -> {new_display}') elif r.status == 'skipped': self._push(f'skipped: {r.old} ({r.detail})') else: diff --git a/telemetry/rename.py b/telemetry/rename.py index 4b9075b..7c44cbb 100644 --- a/telemetry/rename.py +++ b/telemetry/rename.py @@ -115,9 +115,15 @@ def rename_unprocessed(targets: list[str], races_dir: str | None = None) -> list for t in targets: t = os.path.abspath(t) if os.path.isdir(t): - for name in os.listdir(t): - if name.lower().endswith('.csv'): - paths.append(os.path.join(t, name)) + if races_dir is not None: + for root, _, files in os.walk(t): + for fname in sorted(files): + if fname.lower().endswith('.csv'): + paths.append(os.path.join(root, fname)) + else: + for fname in os.listdir(t): + if fname.lower().endswith('.csv'): + paths.append(os.path.join(t, fname)) else: paths.append(t) @@ -131,25 +137,39 @@ def rename_unprocessed(targets: list[str], races_dir: str | None = None) -> list results.append(RenameResult(name, None, 'error', 'not a CSV file')) continue stem = os.path.splitext(name)[0] - if _is_processed(stem): - results.append(RenameResult(name, None, 'skipped', 'already processed')) - continue - try: - lap, session_type, track_name = read_metadata(p) - except Exception as e: - results.append(RenameResult(name, None, 'error', str(e))) - continue - if not session_type: - results.append(RenameResult(name, None, 'error', 'session type not found in CSV')) - continue - new_name = insert_tokens(name, session_type, lap) - if races_dir is not None: - dest_dir = os.path.join(races_dir, _safe_dirname(track_name), _session_folder(session_type)) - os.makedirs(dest_dir, exist_ok=True) + + if races_dir is None: + if _is_processed(stem): + results.append(RenameResult(name, None, 'skipped', 'already processed')) + continue + try: + lap, session_type, _ = read_metadata(p) + except Exception as e: + results.append(RenameResult(name, None, 'error', str(e))) + continue + if not session_type: + results.append(RenameResult(name, None, 'error', 'session type not found in CSV')) + continue + new_name = insert_tokens(name, session_type, lap) + dest = os.path.join(os.path.dirname(p), new_name) else: - dest_dir = os.path.dirname(p) - dest = os.path.join(dest_dir, new_name) - if os.path.exists(dest): + try: + lap, session_type, track_name = read_metadata(p) + except Exception as e: + results.append(RenameResult(name, None, 'error', str(e))) + continue + if not session_type: + results.append(RenameResult(name, None, 'error', 'session type not found in CSV')) + continue + new_name = name if _is_processed(stem) else insert_tokens(name, session_type, lap) + dest_dir = os.path.join(races_dir, _safe_dirname(track_name), _session_folder(session_type)) + dest = os.path.join(dest_dir, new_name) + if os.path.abspath(p) == os.path.abspath(dest): + results.append(RenameResult(name, None, 'skipped', 'already in place')) + continue + os.makedirs(dest_dir, exist_ok=True) + + if os.path.exists(dest) and os.path.abspath(dest) != os.path.abspath(p): results.append(RenameResult(name, dest, 'error', 'target exists')) continue try: diff --git a/tests/test_rename.py b/tests/test_rename.py index a8e0cdd..83e80c7 100644 --- a/tests/test_rename.py +++ b/tests/test_rename.py @@ -139,3 +139,40 @@ def test_rename_unprocessed_moves_to_races_dir(tmp_path, sample_path): assert r.new.startswith(races_dir) assert 'Practice' in r.new assert not os.path.exists(src) + + +def test_rename_unprocessed_moves_already_renamed(tmp_path, sample_path): + """Already-renamed file in wrong folder gets moved to correct folder.""" + src = str(tmp_path / "zandvoort_P1_L7_74.074_ferrari.csv") + shutil.copy(sample_path, src) + races_dir = str(tmp_path / 'races') + results = rename_unprocessed([src], races_dir=races_dir) + assert len(results) == 1 + r = results[0] + assert r.status == 'renamed' + assert 'Practice' in r.new + assert os.path.exists(r.new) + assert not os.path.exists(src) + + +def test_rename_unprocessed_skips_already_in_place(tmp_path, sample_path): + """File already in correct folder is skipped on second run.""" + src = str(tmp_path / "zandvoort_74.074_ferrari.csv") + shutil.copy(sample_path, src) + races_dir = str(tmp_path / 'races') + rename_unprocessed([src], races_dir=races_dir) + results = rename_unprocessed([races_dir], races_dir=races_dir) + assert all(r.status == 'skipped' for r in results) + + +def test_rename_unprocessed_walks_subdirs(tmp_path, sample_path): + """With races_dir, scans subdirectories recursively.""" + sub = tmp_path / 'sub' / 'nested' + sub.mkdir(parents=True) + src = str(sub / "zandvoort_74.074_ferrari.csv") + shutil.copy(sample_path, src) + races_dir = str(tmp_path / 'races') + results = rename_unprocessed([str(tmp_path)], races_dir=races_dir) + assert len(results) == 1 + assert results[0].status == 'renamed' + assert 'Practice' in results[0].new