mirror of
https://github.com/Horizontal42/f1-telemetry.git
synced 2026-11-10 17:42:04 +03:00
rename: recurse subdirs, move already-renamed files to correct folder
When races_dir is set: - os.walk scans all subdirectories of the source - already-renamed files (both tokens present) are also moved if not in the right races/<track>/<session>/ folder - files already in the correct place are skipped with 'already in place' GUI remembers last rename source folder separately from other modes.
This commit is contained in:
parent
818bda26cb
commit
351e9cdf69
3 changed files with 83 additions and 23 deletions
|
|
@ -196,9 +196,11 @@ class _App:
|
||||||
self._log_queue.put(None)
|
self._log_queue.put(None)
|
||||||
|
|
||||||
def _on_rename(self) -> 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:
|
if not d:
|
||||||
return
|
return
|
||||||
|
self._last_dir['rename'] = d
|
||||||
self._set_busy(True)
|
self._set_busy(True)
|
||||||
threading.Thread(target=self._worker_rename, args=(d,), daemon=True).start()
|
threading.Thread(target=self._worker_rename, args=(d,), daemon=True).start()
|
||||||
|
|
||||||
|
|
@ -209,7 +211,8 @@ class _App:
|
||||||
self._push('No CSV files found')
|
self._push('No CSV files found')
|
||||||
for r in results:
|
for r in results:
|
||||||
if r.status == 'renamed':
|
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':
|
elif r.status == 'skipped':
|
||||||
self._push(f'skipped: {r.old} ({r.detail})')
|
self._push(f'skipped: {r.old} ({r.detail})')
|
||||||
else:
|
else:
|
||||||
|
|
|
||||||
|
|
@ -115,9 +115,15 @@ def rename_unprocessed(targets: list[str], races_dir: str | None = None) -> list
|
||||||
for t in targets:
|
for t in targets:
|
||||||
t = os.path.abspath(t)
|
t = os.path.abspath(t)
|
||||||
if os.path.isdir(t):
|
if os.path.isdir(t):
|
||||||
for name in os.listdir(t):
|
if races_dir is not None:
|
||||||
if name.lower().endswith('.csv'):
|
for root, _, files in os.walk(t):
|
||||||
paths.append(os.path.join(t, name))
|
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:
|
else:
|
||||||
paths.append(t)
|
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'))
|
results.append(RenameResult(name, None, 'error', 'not a CSV file'))
|
||||||
continue
|
continue
|
||||||
stem = os.path.splitext(name)[0]
|
stem = os.path.splitext(name)[0]
|
||||||
if _is_processed(stem):
|
|
||||||
results.append(RenameResult(name, None, 'skipped', 'already processed'))
|
if races_dir is None:
|
||||||
continue
|
if _is_processed(stem):
|
||||||
try:
|
results.append(RenameResult(name, None, 'skipped', 'already processed'))
|
||||||
lap, session_type, track_name = read_metadata(p)
|
continue
|
||||||
except Exception as e:
|
try:
|
||||||
results.append(RenameResult(name, None, 'error', str(e)))
|
lap, session_type, _ = read_metadata(p)
|
||||||
continue
|
except Exception as e:
|
||||||
if not session_type:
|
results.append(RenameResult(name, None, 'error', str(e)))
|
||||||
results.append(RenameResult(name, None, 'error', 'session type not found in CSV'))
|
continue
|
||||||
continue
|
if not session_type:
|
||||||
new_name = insert_tokens(name, session_type, lap)
|
results.append(RenameResult(name, None, 'error', 'session type not found in CSV'))
|
||||||
if races_dir is not None:
|
continue
|
||||||
dest_dir = os.path.join(races_dir, _safe_dirname(track_name), _session_folder(session_type))
|
new_name = insert_tokens(name, session_type, lap)
|
||||||
os.makedirs(dest_dir, exist_ok=True)
|
dest = os.path.join(os.path.dirname(p), new_name)
|
||||||
else:
|
else:
|
||||||
dest_dir = os.path.dirname(p)
|
try:
|
||||||
dest = os.path.join(dest_dir, new_name)
|
lap, session_type, track_name = read_metadata(p)
|
||||||
if os.path.exists(dest):
|
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'))
|
results.append(RenameResult(name, dest, 'error', 'target exists'))
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
|
|
|
||||||
|
|
@ -139,3 +139,40 @@ def test_rename_unprocessed_moves_to_races_dir(tmp_path, sample_path):
|
||||||
assert r.new.startswith(races_dir)
|
assert r.new.startswith(races_dir)
|
||||||
assert 'Practice' in r.new
|
assert 'Practice' in r.new
|
||||||
assert not os.path.exists(src)
|
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
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue