Skip to content

Commit b0105e2

Browse files
authored
Merge pull request #239 from bogdant36/CTX-6421
CTX-6421: Fixed bug where temp folder is not cleaned after run is finished. (refactor of folder_manager)
2 parents 23b02b6 + 275b28e commit b0105e2

File tree

19 files changed

+208
-214
lines changed

19 files changed

+208
-214
lines changed

coretex/__init__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,3 +34,4 @@
3434
# Use this only
3535
from .entities import *
3636
from ._task import currentTaskRun, initializeRTask, TaskRunWorker
37+
from ._folder_manager import folder_manager

coretex/_folder_manager.py

Lines changed: 188 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,188 @@
1+
# Copyright (C) 2023 Coretex LLC
2+
3+
# This file is part of Coretex.ai
4+
5+
# This program is free software: you can redistribute it and/or modify
6+
# it under the terms of the GNU Affero General Public License as
7+
# published by the Free Software Foundation, either version 3 of the
8+
# License, or (at your option) any later version.
9+
10+
# This program is distributed in the hope that it will be useful,
11+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
12+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13+
# GNU Affero General Public License for more details.
14+
15+
# You should have received a copy of the GNU Affero General Public License
16+
# along with this program. If not, see <https://www.gnu.org/licenses/>.
17+
18+
from typing import Iterator, Optional, Union
19+
from pathlib import Path
20+
from contextlib import contextmanager
21+
22+
import os
23+
import shutil
24+
import uuid
25+
26+
27+
class FolderManager:
28+
29+
"""
30+
Used for handling everything related to local storage
31+
when working with Coretex
32+
33+
Contains
34+
--------
35+
samplesFolder : Path
36+
folder where samples are stored
37+
modelsFolder : Path
38+
folder where models are stored
39+
temp : Path
40+
folder where temp files and folders are stored,
41+
this is deleted when the run has finished executing
42+
datasetsFolder : Path
43+
folder where datasets are stored (samples are symlinked for datasets)
44+
cache : Path
45+
folder where cache module stores items
46+
logs : Path
47+
folder where node and run logs are stored
48+
environments : Path
49+
folder where node stores python environments
50+
"""
51+
52+
def __init__(self, storagePath: Union[Path, str]):
53+
if isinstance(storagePath, str):
54+
storagePath = Path(storagePath)
55+
56+
self._root = storagePath.expanduser()
57+
58+
self.samplesFolder = self._createFolder("samples")
59+
self.modelsFolder = self._createFolder("models")
60+
self.datasetsFolder = self._createFolder("datasets")
61+
self.cache = self._createFolder("cache")
62+
self.logs = self._createFolder("logs")
63+
self.environments = self._createFolder("environments")
64+
self.temp = self._createFolder("temp")
65+
self._artifactsFolder = self._createFolder("artifacts")
66+
67+
self.runsLogDirectory = self.logs / "runs"
68+
self.runsLogDirectory.mkdir(exist_ok = True)
69+
70+
self.coretexpylibLogs = self.logs / "coretexpylib"
71+
self.coretexpylibLogs.mkdir(exist_ok = True)
72+
73+
def _createFolder(self, name: str) -> Path:
74+
path = self._root / name
75+
76+
if not path.exists():
77+
path.mkdir(parents = True, exist_ok = True)
78+
79+
return path
80+
81+
def createTempFolder(self, name: str) -> Path:
82+
"""
83+
Creates temp folder which is deleted once
84+
the run has finished executing
85+
86+
Parameters
87+
----------
88+
name : str
89+
name of the folder
90+
91+
Returns
92+
-------
93+
Path -> path to the created folder
94+
95+
Raises
96+
------
97+
FileExistsError -> if the temp folder already exists
98+
99+
Example
100+
-------
101+
>>> from coretex import folder_manager
102+
\b
103+
>>> dummyFolderPath = folder_manager.createTempFolder("dummyTempFolder")
104+
>>> print(dummyFolderPath)
105+
"/Users/X/.coretex/temp/dummyTempFolder"
106+
"""
107+
108+
tempFolderPath = self.temp / name
109+
110+
if tempFolderPath.exists():
111+
raise FileExistsError
112+
113+
tempFolderPath.mkdir()
114+
return tempFolderPath
115+
116+
def getArtifactsFolder(self, taskRunId: int) -> Path:
117+
"""
118+
Retrieves the path to where the artifacts are stored
119+
for the specified TaskRuns
120+
121+
Parameters
122+
----------
123+
taskRunId : int
124+
id of the TaskRun
125+
126+
Returns
127+
-------
128+
Path -> path to the TaskRun artifacts local storage
129+
130+
Example
131+
-------
132+
>>> from coretex.folder_management import FolderManager
133+
\b
134+
>>> artifactsFolderPath = FolderManager.instance().getArtifactsFolder(1023)
135+
>>> print(artifactsFolderPath)
136+
Path("/Users/bogdanbm/.coretex/artifacts/1023")
137+
"""
138+
139+
return self._artifactsFolder / str(taskRunId)
140+
141+
def clearDirectory(self, path: Path) -> None:
142+
shutil.rmtree(path)
143+
path.mkdir()
144+
145+
def clearTempFiles(self) -> None:
146+
"""
147+
Deletes all temp files and folders (including artifacts)
148+
"""
149+
150+
self.clearDirectory(self.temp)
151+
self.clearDirectory(self._artifactsFolder)
152+
153+
def getRunLogsDir(self, taskRunId: int) -> Path:
154+
taskRunLogsDir = self.runsLogDirectory / str(taskRunId)
155+
taskRunLogsDir.mkdir(parents = True, exist_ok = True)
156+
157+
return taskRunLogsDir
158+
159+
@contextmanager
160+
def tempFile(self, name: Optional[str] = None) -> Iterator[Path]:
161+
"""
162+
Returns a path to temporary file and deletes
163+
it if it exists once the context is exited.
164+
165+
Parameters
166+
----------
167+
name : Optional[str]
168+
Name of the file. If not specified a random uuid4
169+
will be generated and used as the name
170+
171+
Returns
172+
-------
173+
Iterator[Path] -> path to the file
174+
"""
175+
176+
if name is None:
177+
name = str(uuid.uuid4())
178+
179+
path = self.temp / name
180+
if path.exists():
181+
raise FileExistsError(path)
182+
try:
183+
yield path
184+
finally:
185+
path.unlink(missing_ok = True)
186+
187+
188+
folder_manager = FolderManager(os.environ["CTX_STORAGE_PATH"])

coretex/_logger.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717

1818
from datetime import datetime
1919

20-
from . import folder_manager
20+
from ._folder_manager import folder_manager
2121
from .logging import initializeLogger, LogSeverity
2222
from .configuration import CONFIG_DIR
2323

coretex/_task/base_callback.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import signal
2424

2525
from .current_task_run import setCurrentTaskRun
26-
from .. import folder_manager
26+
from .._folder_manager import folder_manager
2727
from ..entities import TaskRun
2828

2929

coretex/_task/initialization.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
from .remote import processRemote
2424
from .current_task_run import setCurrentTaskRun
25-
from .. import folder_manager
25+
from .._folder_manager import folder_manager
2626
from ..entities import TaskRun, TaskRunStatus
2727
from ..logging import createFormatter, initializeLogger
2828
from ..logging.severity import LogSeverity

coretex/_task/worker/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import logging
2121

22-
from ... import folder_manager
22+
from ..._folder_manager import folder_manager
2323
from ...utils import createFileHandler
2424

2525

coretex/bioinformatics/ctx_qiime2/utils.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import shutil
2424
import gzip
2525

26-
from ... import folder_manager
26+
from ..._folder_manager import folder_manager
2727
from ...entities import TaskRun, CustomSample, CustomDataset
2828
from ...networking import NetworkRequestError
2929

coretex/cache.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
import requests
2727

28-
from . import folder_manager
28+
from ._folder_manager import folder_manager
2929

3030

3131
class CacheException(Exception):

coretex/cli/commands/task.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222
from ..modules.user import initializeUserSession
2323
from ..modules.utils import onBeforeCommandExecute
2424
from ..modules.project_utils import getProject
25-
from ... import folder_manager
25+
from ..._folder_manager import FolderManager
2626
from ..._task import TaskRunWorker, executeRunLocally, readTaskConfig, runLogger
2727
from ...configuration import loadConfig
2828
from ...entities import TaskRun, TaskRunStatus
@@ -45,7 +45,8 @@ def run(path: str, name: Optional[str], description: Optional[str], snapshot: bo
4545
parameters = readTaskConfig()
4646

4747
# clearing temporary files in case that node was manually killed before
48-
folder_manager.clearTempFiles()
48+
folderManager = FolderManager(config["storagePath"])
49+
folderManager.clearTempFiles()
4950

5051
selectedProject = getProject(project, config)
5152
if selectedProject is None:
@@ -87,4 +88,4 @@ def run(path: str, name: Optional[str], description: Optional[str], snapshot: bo
8788
else:
8889
taskRun.updateStatus(TaskRunStatus.completedWithSuccess)
8990

90-
folder_manager.clearTempFiles()
91+
folderManager.clearTempFiles()

coretex/entities/dataset/image_dataset/synthetic_image_generator.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
from .base import BaseImageDataset
3333
from ...sample import ImageSample, AnnotatedImageSampleData
3434
from ...annotation import CoretexSegmentationInstance, CoretexImageAnnotation, BBox
35-
from .... import folder_manager
35+
from ...._folder_manager import folder_manager
3636

3737

3838
ANNOTATION_NAME = "annotations.json"

0 commit comments

Comments
 (0)