Simon Strandgaard commited on
Commit
e49f146
·
1 Parent(s): bd55e57

purge_old_runs() added

Browse files
src/purge/__init__.py ADDED
File without changes
src/purge/purge_old_runs.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import logging
2
+ import os
3
+ import shutil
4
+ import datetime
5
+
6
+ logger = logging.getLogger(__name__)
7
+
8
+ def purge_old_runs(run_dir: str, max_age_hours: float = 1.0) -> None:
9
+ """
10
+ Deletes runs in the specified run_dir older than max_age_hours.
11
+ """
12
+ # raise exception if the run_dir is not an absolute path
13
+ if not os.path.isabs(run_dir):
14
+ raise ValueError(f"run_dir must be an absolute path: {run_dir}")
15
+
16
+ now = datetime.datetime.now()
17
+ cutoff = now - datetime.timedelta(hours=max_age_hours)
18
+
19
+ for run_id in os.listdir(run_dir):
20
+ run_path = os.path.join(run_dir, run_id)
21
+ if not os.path.isdir(run_path):
22
+ continue # Skip files
23
+
24
+ try:
25
+ # Get the modification time of the directory
26
+ mtime = datetime.datetime.fromtimestamp(os.path.getmtime(run_path))
27
+
28
+ if mtime < cutoff:
29
+ logger.debug(f"Deleting old run: {run_id} from {run_dir}")
30
+ shutil.rmtree(run_path) # Delete the directory and all its contents
31
+ else:
32
+ logger.debug(f"Skipping {run_id} in {run_dir}, last modified: {mtime}")
33
+
34
+ except Exception as e:
35
+ logger.error(f"Error processing {run_id} in {run_dir}: {e}")
src/purge/tests/__init__.py ADDED
File without changes
src/purge/tests/test_purge_old_runs.py ADDED
@@ -0,0 +1,85 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import unittest
2
+ import os
3
+ import shutil
4
+ import time
5
+ from src.purge.purge_old_runs import purge_old_runs
6
+
7
+ class TestPurgeOldRuns(unittest.TestCase):
8
+ def setUp(self):
9
+ """
10
+ Set up test environment before each test.
11
+ """
12
+ # Create a temporary directory for the runs
13
+ self.test_run_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "test_run"))
14
+ if os.path.exists(self.test_run_dir):
15
+ shutil.rmtree(self.test_run_dir)
16
+ os.makedirs(self.test_run_dir, exist_ok=True)
17
+
18
+ # Create some dummy run directories with different modification times
19
+ self.create_dummy_run("run1", hours_old=0.5)
20
+ self.create_dummy_run("run2", hours_old=1.5) # Should be purged
21
+ self.create_dummy_run("run3", hours_old=2) # Should be purged
22
+ self.create_dummy_run("run4", hours_old=0.25)
23
+ self.create_dummy_run("run5", hours_old=1) # Boundary condition, might be purged
24
+ self.create_dummy_run("run6", hours_old=0) # Today
25
+ self.create_dummy_file("not_a_run.txt") # a file that should be left alone
26
+
27
+ def tearDown(self):
28
+ """
29
+ Clean up test environment after each test.
30
+ """
31
+ # Remove the temporary run directory and its contents
32
+ if os.path.exists(self.test_run_dir):
33
+ shutil.rmtree(self.test_run_dir)
34
+
35
+ def create_dummy_run(self, run_id, hours_old):
36
+ """
37
+ Creates a dummy run directory with a specific modification time.
38
+ """
39
+ run_path = os.path.join(self.test_run_dir, run_id)
40
+ os.makedirs(run_path, exist_ok=True)
41
+
42
+ # Set the modification time of the directory
43
+ mtime = time.time() - (hours_old * 3600) # seconds
44
+ os.utime(run_path, (mtime, mtime))
45
+
46
+ def create_dummy_file(self, filename):
47
+ """Create a dummy file in the test directory."""
48
+ filepath = os.path.join(self.test_run_dir, filename)
49
+ with open(filepath, "w") as f:
50
+ f.write("This is a dummy file.")
51
+
52
+ def test_purge_old_runs(self):
53
+ """Tests the purge_old_runs function."""
54
+ max_age_hours = 0.95
55
+ purge_old_runs(self.test_run_dir, max_age_hours=max_age_hours) # Pass the directory
56
+
57
+ # Check which runs should have been purged
58
+ runs_to_keep = ["run1", "run4", "run6", "not_a_run.txt"]
59
+ runs_to_purge = ["run2", "run3", "run5"]
60
+
61
+ for run_id in runs_to_keep:
62
+ run_path = os.path.join(self.test_run_dir, run_id)
63
+ self.assertTrue(os.path.exists(run_path), f"Run {run_id} should not have been purged.")
64
+
65
+ for run_id in runs_to_purge:
66
+ run_path = os.path.join(self.test_run_dir, run_id)
67
+ self.assertFalse(os.path.exists(run_path), f"Run {run_id} should have been purged.")
68
+
69
+ def test_purge_no_runs(self):
70
+ """Test when no runs are older than the max_age_hours."""
71
+
72
+ # Set all runs to be very recent.
73
+ for item in os.listdir(self.test_run_dir):
74
+ item_path = os.path.join(self.test_run_dir, item)
75
+ mtime = time.time() # Now
76
+ os.utime(item_path, (mtime, mtime))
77
+
78
+ max_age_hours = 1.0
79
+ purge_old_runs(self.test_run_dir, max_age_hours=max_age_hours) # Pass the directory
80
+
81
+ # All runs should still exist.
82
+ expected_runs = ["run1", "run2", "run3", "run4", "run5", "run6", "not_a_run.txt"]
83
+ for run_id in expected_runs:
84
+ run_path = os.path.join(self.test_run_dir, run_id)
85
+ self.assertTrue(os.path.exists(run_path), f"Run {run_id} should not have been purged.")