Skip to content

Commit 2ce5d88

Browse files
added destination to case.results.download() functionality. Removed other download methods
applied PR comments fixed black removed unused import
1 parent 7e62696 commit 2ce5d88

File tree

10 files changed

+198
-334
lines changed

10 files changed

+198
-334
lines changed

examples/case_results.py

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,12 @@
2727
print(case.results.minmax_state.raw)
2828

2929
# download all result files of the case:
30-
case.results.download_manager(all=True)
30+
downloaded_files = case.results.download(all=True, destination=case.name)
31+
print(downloaded_files)
3132

32-
# download specific result files of the case:
33-
case.results.download_manager(bet_forces=True, actuator_disk_output=True)
34-
35-
# alternative way of downloading using dedicated functions:
36-
case.results.download_surface()
37-
case.results.download_volumetric()
3833

34+
# download specific result files of the case:
35+
case.results.download(bet_forces=True, actuator_disk_output=True)
3936

4037
try:
4138
case.results.total_forces.plot()

flow360/cloud/s3_utils.py

Lines changed: 49 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
)
2424

2525
from ..environment import Env
26-
from ..exceptions import CloudFileError
26+
from ..exceptions import ValueError as FlValueError
2727
from ..log import log
2828
from .http_util import http
2929

@@ -52,17 +52,47 @@ def __call__(self, bytes_chunk_transferred):
5252
)
5353

5454

55-
def create_base_folder(path: str, target_name: str, to_file: str = ".", keep_folder: bool = True):
55+
def create_base_folder(
56+
path: str, target_name: str, to_file: str = ".", to_folder: str = ".", keep_folder: bool = True
57+
):
5658
"""
57-
:param path: source id
58-
:param target_name: path to file on cloud, same value as key for s3 client download.
59-
:param to_file: could be either folder or file name.
60-
:param keep_folder: If true, the downloaded file will
61-
be put in the same folder as the file on cloud. Only work
62-
when file_name is a folder name.
63-
:return:
59+
Create a base folder and return the target file path for downloading cloud data.
60+
61+
Parameters
62+
----------
63+
path : str
64+
Source ID or the path to the source file on the cloud.
65+
66+
target_name : str
67+
The file path on the cloud, same value as the key for S3 client download.
68+
69+
to_file : str, optional
70+
The destination folder or file path where the downloaded file will be saved. If None, the current directory
71+
will be used.
72+
73+
to_folder : str, optional
74+
The folder name to save the downloaded file. If provided, the downloaded file will be saved inside this folder.
75+
If None, the value of `to_file` will be considered as a folder or file path.
76+
77+
keep_folder : bool, optional
78+
If True, the downloaded file will be put in the same folder as the file on the cloud (only works when
79+
`target_name` is a folder name).
80+
81+
Returns
82+
-------
83+
str
84+
The target file path for downloading cloud data.
85+
6486
"""
65-
if os.path.isdir(to_file):
87+
88+
if to_folder != ".":
89+
to_file = (
90+
os.path.join(to_folder, target_name)
91+
if keep_folder
92+
else os.path.join(to_folder, os.path.basename(target_name))
93+
)
94+
95+
elif os.path.isdir(to_file):
6696
to_file = (
6797
os.path.join(to_file, path, target_name)
6898
if keep_folder
@@ -226,7 +256,8 @@ def download_file(
226256
self,
227257
resource_id: str,
228258
remote_file_name: str,
229-
to_file: str,
259+
to_file: str = ".",
260+
to_folder: str = ".",
230261
keep_folder: bool = True,
231262
overwrite: bool = True,
232263
progress_callback=None,
@@ -243,10 +274,14 @@ def download_file(
243274
:param progress_callback: provide custom callback for progress
244275
:return:
245276
"""
246-
to_file = create_base_folder(resource_id, remote_file_name, to_file, keep_folder)
277+
if to_file != "." and to_folder != ".":
278+
raise FlValueError("Only one of 'to_file' or 'to_folder' should be provided, not both.")
279+
280+
to_file = create_base_folder(resource_id, remote_file_name, to_file, to_folder, keep_folder)
247281
if os.path.exists(to_file) and not overwrite:
248282
log.info(f"Skipping {remote_file_name}, file exists.")
249-
return
283+
return to_file
284+
250285
token = self._get_s3_sts_token(resource_id, remote_file_name)
251286
client = token.get_client()
252287
try:
@@ -283,6 +318,7 @@ def _call_back(bytes_in_chunk):
283318
Callback=_call_back,
284319
)
285320
log.info(f"Saved to {to_file}")
321+
return to_file
286322

287323
def _get_s3_sts_token(self, resource_id: str, file_name: str) -> _S3STSToken:
288324
session_key = f"{resource_id}:{self.value}:{file_name}"

flow360/component/case.py

Lines changed: 81 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -447,18 +447,6 @@ def results(self) -> CaseResults:
447447
"""
448448
return self._results
449449

450-
def download_log(self, log_file, to_file=".", keep_folder: bool = True):
451-
"""
452-
Download log
453-
:param log_file:
454-
:param to_file: file name on local disk, could be either folder or file name.
455-
:param keep_folder: If true, the downloaded file will be put in the same folder as the file on cloud. Only work
456-
when file_name is a folder name.
457-
:return:
458-
"""
459-
460-
self.download_file(f"logs/{log_file.value}", to_file, keep_folder)
461-
462450
def is_steady(self):
463451
"""
464452
returns True when case is steady state
@@ -770,30 +758,52 @@ def plot(self):
770758
"""
771759
return self._plotter
772760

773-
def download_file(self, downloadable: CaseDownloadable, overwrite: bool = True, **kwargs):
774-
"""
775-
download specific file by filename
776-
:param downloadable: filename to download
777-
:param overwrite: when True, overwrites existing file, otherwise skip
761+
# pylint: disable=protected-access
762+
def _download_file(
763+
self,
764+
downloadable: CaseDownloadable,
765+
to_file=".",
766+
to_folder=".",
767+
overwrite: bool = True,
768+
**kwargs,
769+
):
778770
"""
779-
return self._case.download_file(
780-
f"results/{downloadable.value}", overwrite=overwrite, **kwargs
781-
)
771+
Download a specific file associated with the case.
782772
783-
def download_volumetric(self):
784-
"""
785-
download volumetric results data
786-
"""
787-
self.download_file(CaseDownloadable.VOLUME)
773+
Parameters
774+
----------
775+
downloadable : flow360.CaseDownloadable
776+
The type of file to be downloaded (e.g., surface, volume, forces, etc.).
788777
789-
def download_surface(self):
790-
"""
791-
download surface results data
778+
to_file : str, optional
779+
File path to save the downloaded file. If None, the file will be saved in the current directory.
780+
If provided without an extension, the extension will be automatically added based on the file type.
781+
782+
to_folder : str, optional
783+
Folder name to save the downloaded file. If None, the file will be saved in the current directory.
784+
785+
overwrite : bool, optional
786+
If True, overwrite existing files with the same name in the destination.
787+
788+
**kwargs : dict, optional
789+
Additional arguments to be passed to the download process.
790+
791+
Returns
792+
-------
793+
str
794+
File path of the downloaded file.
792795
"""
793-
self.download_file(CaseDownloadable.SURFACE)
796+
797+
return self._case._download_file(
798+
f"results/{downloadable.value}",
799+
to_file=to_file,
800+
to_folder=to_folder,
801+
overwrite=overwrite,
802+
**kwargs,
803+
)
794804

795805
# pylint: disable=redefined-builtin,too-many-locals,too-many-arguments
796-
def download_manager(
806+
def download(
797807
self,
798808
surface: bool = False,
799809
volume: bool = False,
@@ -807,42 +817,44 @@ def download_manager(
807817
actuator_disk_output: bool = False,
808818
all: bool = False,
809819
overwrite: bool = False,
820+
destination: str = ".",
810821
):
811-
"""download manager for downloading many files at once
822+
"""
823+
Download result files associated with the case.
812824
813825
Parameters
814826
----------
815827
surface : bool, optional
816-
_description_, by default False
828+
Download surface result file if True.
817829
volume : bool, optional
818-
_description_, by default False
830+
Download volume result file if True.
819831
nonlinear_residuals : bool, optional
820-
_description_, by default False
832+
Download nonlinear residuals file if True.
821833
linear_residuals : bool, optional
822-
_description_, by default False
834+
Download linear residuals file if True.
823835
cfl : bool, optional
824-
_description_, by default False
836+
Download CFL file if True.
825837
minmax_state : bool, optional
826-
_description_, by default False
838+
Download minmax state file if True.
827839
surface_forces : bool, optional
828-
_description_, by default False
840+
Download surface forces file if True.
829841
total_forces : bool, optional
830-
_description_, by default False
842+
Download total forces file if True.
831843
bet_forces : bool, optional
832-
_description_, by default False
844+
Download BET (Blade Element Theory) forces file if True.
833845
actuator_disk_output : bool, optional
834-
_description_, by default False
846+
Download actuator disk output file if True.
835847
all : bool, optional
836-
_description_, by default False
848+
Download all result files if True (ignores other parameters).
837849
overwrite : bool, optional
838-
_description_, by default False
850+
If True, overwrite existing files with the same name in the destination.
851+
destination : str, optional
852+
Location to save downloaded files. If None, files will be saved in the current directory under ID folder.
839853
840-
Raises
841-
------
842-
e
843-
_description_
844-
e
845-
_description_
854+
Returns
855+
-------
856+
List of str
857+
File paths of the downloaded files.
846858
"""
847859

848860
download_map = [
@@ -855,15 +867,22 @@ def download_manager(
855867
(surface_forces, CaseDownloadable.SURFACE_FORCES),
856868
(total_forces, CaseDownloadable.TOTAL_FORCES),
857869
]
858-
870+
downloaded_files = []
859871
for do_download, filename in download_map:
860872
if do_download or all:
861-
self.download_file(filename, overwrite=overwrite)
873+
downloaded_files.append(
874+
self._download_file(filename, to_folder=destination, overwrite=overwrite)
875+
)
862876

863877
if bet_forces or all:
864878
try:
865-
self.download_file(
866-
CaseDownloadable.BET_FORCES, overwrite=overwrite, log_error=False
879+
downloaded_files.append(
880+
self._download_file(
881+
CaseDownloadable.BET_FORCES,
882+
to_folder=destination,
883+
overwrite=overwrite,
884+
log_error=False,
885+
)
867886
)
868887
except CloudFileNotFoundError as err:
869888
if not self._case.has_bet_disks():
@@ -877,8 +896,13 @@ def download_manager(
877896

878897
if actuator_disk_output or all:
879898
try:
880-
self.download_file(
881-
CaseDownloadable.ACTUATOR_DISK_OUTPUT, overwrite=overwrite, log_error=False
899+
downloaded_files.append(
900+
self._download_file(
901+
CaseDownloadable.ACTUATOR_DISK_OUTPUT,
902+
to_folder=destination,
903+
overwrite=overwrite,
904+
log_error=False,
905+
)
882906
)
883907
except CloudFileNotFoundError as err:
884908
if not self._case.has_actuator_disks():
@@ -893,6 +917,8 @@ def download_manager(
893917
)
894918
raise err
895919

920+
return downloaded_files
921+
896922

897923
class CaseList(Flow360ResourceListBase):
898924
"""

0 commit comments

Comments
 (0)