pybiolib 1.1.1979__py3-none-any.whl → 1.1.1984__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -3,12 +3,11 @@ import os
3
3
  import stat
4
4
  from datetime import datetime, timezone
5
5
  from time import time
6
- from typing import Iterable
7
6
 
8
7
  from biolib._internal.libs.fusepy import FUSE, FuseOSError, Operations
9
8
  from biolib.biolib_errors import BioLibError
10
9
  from biolib.jobs import Job
11
- from biolib.typing_utils import Dict, Optional, Tuple, TypedDict
10
+ from biolib.typing_utils import Dict, List, Optional, Tuple, TypedDict
12
11
 
13
12
 
14
13
  class _AttributeDict(TypedDict):
@@ -27,7 +26,6 @@ class ExperimentFuseMount(Operations):
27
26
  self._experiment = experiment
28
27
  self._job_names_map: Optional[Dict[str, Job]] = None
29
28
  self._jobs_last_fetched_at: float = 0.0
30
- self._root_path: str = '/'
31
29
  self._mounted_at_epoch_seconds: int = int(time())
32
30
 
33
31
  @staticmethod
@@ -41,80 +39,77 @@ class ExperimentFuseMount(Operations):
41
39
  )
42
40
 
43
41
  def getattr(self, path: str, fh=None) -> _AttributeDict:
44
- full_path = self._full_path(path)
45
- if full_path == '/':
46
- # return folder dir
47
- return self._get_folder_attr(timestamp_epoch_seconds=self._mounted_at_epoch_seconds)
48
-
49
- job_name, job_path = self._parse_path(path)
50
- job = self._get_job_names_map().get(job_name)
51
- if not job:
52
- # job not found
53
- raise FuseOSError(errno.ENOENT)
42
+ if path == '/':
43
+ return self._get_directory_attributes(timestamp_epoch_seconds=self._mounted_at_epoch_seconds)
54
44
 
45
+ job, path_in_job = self._parse_path(path)
55
46
  job_finished_at_epoch_seconds: int = int(
56
47
  datetime.fromisoformat(job.to_dict()['finished_at'].rstrip('Z')).replace(tzinfo=timezone.utc).timestamp()
57
48
  )
58
- if not job_path or job_path == '/':
59
- # job root path
60
- return self._get_folder_attr(timestamp_epoch_seconds=job_finished_at_epoch_seconds)
49
+
50
+ if path_in_job == '/':
51
+ return self._get_directory_attributes(timestamp_epoch_seconds=job_finished_at_epoch_seconds)
61
52
 
62
53
  try:
63
- file = job.get_output_file(job_path)
54
+ file = job.get_output_file(path_in_job)
55
+ return self._get_file_attributes(
56
+ timestamp_epoch_seconds=job_finished_at_epoch_seconds,
57
+ size_in_bytes=file.length,
58
+ )
64
59
  except BioLibError:
65
60
  # file not found
66
- raise FuseOSError(errno.ENOENT) from None
61
+ pass
67
62
 
68
- return _AttributeDict(
69
- st_atime=job_finished_at_epoch_seconds,
70
- st_ctime=job_finished_at_epoch_seconds,
71
- st_gid=os.getgid(),
72
- st_mode=stat.S_IFREG | 0o444, # Regular file with read permissions for owner, group, and others.
73
- st_mtime=job_finished_at_epoch_seconds,
74
- st_nlink=1,
75
- st_size=file.length,
76
- st_uid=os.getuid(),
77
- )
63
+ file_paths_in_job = [file.path for file in job.list_output_files()]
64
+
65
+ for file_path_in_job in file_paths_in_job:
66
+ if file_path_in_job.startswith(path_in_job):
67
+ return self._get_directory_attributes(timestamp_epoch_seconds=job_finished_at_epoch_seconds)
78
68
 
79
- def readdir(self, path: str, fh: int) -> Iterable[str]:
69
+ raise FuseOSError(errno.ENOENT) from None # No such file or directory
70
+
71
+ def readdir(self, path: str, fh: int) -> List[str]:
80
72
  directory_entries = ['.', '..']
73
+
81
74
  if path == '/':
82
- for name in self._get_job_names_map(refresh_jobs=True):
83
- directory_entries.append(name)
75
+ directory_entries.extend(self._get_job_names_map(refresh_jobs=True).keys())
84
76
  else:
85
- job_name, job_path = self._parse_path(path)
86
- job = self._get_job_names_map()[job_name]
87
- in_target_directory = set(
88
- [k.path.split('/')[1] for k in job.list_output_files() if k.path.startswith(job_path)]
77
+ job, path_in_job = self._parse_path(path)
78
+ dir_path_in_job = '/' if path_in_job == '/' else path_in_job + '/'
79
+ depth = dir_path_in_job.count('/')
80
+ directory_entries.extend(
81
+ set(
82
+ [
83
+ file.path.split('/')[depth]
84
+ for file in job.list_output_files()
85
+ if file.path.startswith(dir_path_in_job)
86
+ ]
87
+ )
89
88
  )
90
89
 
91
- for key in in_target_directory:
92
- directory_entries.append(key)
93
-
94
- yield from directory_entries
90
+ return directory_entries
95
91
 
96
92
  def open(self, path: str, flags: int) -> int:
97
- job_name, job_path = self._parse_path(path)
98
- job = self._get_job_names_map()[job_name]
93
+ job, path_in_job = self._parse_path(path)
99
94
  try:
100
- job.get_output_file(job_path)
101
- return 0 # return dummy file handle
95
+ job.get_output_file(path_in_job)
102
96
  except BioLibError:
103
97
  # file not found
104
98
  raise FuseOSError(errno.ENOENT) from None
105
99
 
100
+ return 0 # return dummy file handle
101
+
106
102
  def read(self, path: str, size: int, offset: int, fh: int) -> bytes:
107
- job_name, job_path = self._parse_path(path)
108
- job = self._get_job_names_map()[job_name]
103
+ job, path_in_job = self._parse_path(path)
109
104
  try:
110
- file = job.get_output_file(job_path)
105
+ file = job.get_output_file(path_in_job)
111
106
  except BioLibError:
112
- # file not found
113
- raise FuseOSError(errno.ENOENT) from None
107
+ raise FuseOSError(errno.ENOENT) from None # No such file or directory
114
108
 
115
109
  return file.get_data(start=offset, length=size)
116
110
 
117
- def _get_folder_attr(self, timestamp_epoch_seconds: int) -> _AttributeDict:
111
+ @staticmethod
112
+ def _get_directory_attributes(timestamp_epoch_seconds: int) -> _AttributeDict:
118
113
  return _AttributeDict(
119
114
  st_atime=timestamp_epoch_seconds,
120
115
  st_ctime=timestamp_epoch_seconds,
@@ -126,6 +121,19 @@ class ExperimentFuseMount(Operations):
126
121
  st_uid=os.getuid(),
127
122
  )
128
123
 
124
+ @staticmethod
125
+ def _get_file_attributes(timestamp_epoch_seconds: int, size_in_bytes: int) -> _AttributeDict:
126
+ return _AttributeDict(
127
+ st_atime=timestamp_epoch_seconds,
128
+ st_ctime=timestamp_epoch_seconds,
129
+ st_gid=os.getgid(),
130
+ st_mode=stat.S_IFREG | 0o444, # Regular file with read permissions for owner, group, and others.
131
+ st_mtime=timestamp_epoch_seconds,
132
+ st_nlink=1,
133
+ st_size=size_in_bytes,
134
+ st_uid=os.getuid(),
135
+ )
136
+
129
137
  def _get_job_names_map(self, refresh_jobs=False) -> Dict[str, Job]:
130
138
  current_time = time()
131
139
  if not self._job_names_map or (current_time - self._jobs_last_fetched_at > 1 and refresh_jobs):
@@ -134,18 +142,15 @@ class ExperimentFuseMount(Operations):
134
142
 
135
143
  return self._job_names_map
136
144
 
137
- def _full_path(self, partial: str) -> str:
138
- if partial.startswith('/'):
139
- partial = partial[1:]
140
-
141
- return os.path.join(self._root_path, partial)
145
+ def _parse_path(self, path: str) -> Tuple[Job, str]:
146
+ path_splitted = path.split('/')
147
+ job_name = path_splitted[1]
148
+ path_in_job = '/' + '/'.join(path_splitted[2:])
149
+ job = self._get_job_names_map().get(job_name)
150
+ if not job:
151
+ raise FuseOSError(errno.ENOENT) # No such file or directory
142
152
 
143
- def _parse_path(self, path: str) -> Tuple[str, str]:
144
- full_path = self._full_path(path)
145
- full_path_splitted = full_path.split('/')
146
- job_name = full_path_splitted[1]
147
- job_path = '/'.join(full_path_splitted[2:])
148
- return job_name, job_path
153
+ return job, path_in_job
149
154
 
150
155
  # ----------------------------------- File system methods not implemented below -----------------------------------
151
156
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pybiolib
3
- Version: 1.1.1979
3
+ Version: 1.1.1984
4
4
  Summary: BioLib Python Client
5
5
  Home-page: https://github.com/biolib
6
6
  License: MIT
@@ -6,7 +6,7 @@ biolib/_internal/data_record/__init__.py,sha256=1Bk303i3rFet9veS56fIsrBYtT5X3n9v
6
6
  biolib/_internal/data_record/data_record.py,sha256=ctijrrZ-LfUxtwzS8PEVa1VBuBLVWEhmo2yHcEDkC0A,7178
7
7
  biolib/_internal/data_record/remote_storage_endpoint.py,sha256=LPq8Lr5FhKF9_o5K-bUdT7TeLe5XFUD0AAeTkNEVZug,1133
8
8
  biolib/_internal/fuse_mount/__init__.py,sha256=B_tM6RM2dBw-vbpoHJC4X3tOAaN1H2RDvqYJOw3xFwg,55
9
- biolib/_internal/fuse_mount/experiment_fuse_mount.py,sha256=tRkgPncbf9Nl22adcjBTJuFfiYMkayYJSJ--WQrB-Ps,6629
9
+ biolib/_internal/fuse_mount/experiment_fuse_mount.py,sha256=DcR2NyUyZYgpsaKM1WBJZChAaD2vvt_vvZCXj-P2UTs,6878
10
10
  biolib/_internal/http_client.py,sha256=DdooXei93JKGYGV4aQmzue_oFzvHkozg2UCxgk9dfDM,5081
11
11
  biolib/_internal/libs/__init__.py,sha256=Jdf4tNPqe_oIIf6zYml6TiqhL_02Vyqwge6IELrAFhw,98
12
12
  biolib/_internal/libs/fusepy/__init__.py,sha256=AWDzNFS-XV_5yKb0Qx7kggIhPzq1nj_BZS5y2Nso08k,41944
@@ -109,8 +109,8 @@ biolib/utils/cache_state.py,sha256=u256F37QSRIVwqKlbnCyzAX4EMI-kl6Dwu6qwj-Qmag,3
109
109
  biolib/utils/multipart_uploader.py,sha256=XvGP1I8tQuKhAH-QugPRoEsCi9qvbRk-DVBs5PNwwJo,8452
110
110
  biolib/utils/seq_util.py,sha256=jC5WhH63FTD7SLFJbxQGA2hOt9NTwq9zHl_BEec1Z0c,4907
111
111
  biolib/utils/zip/remote_zip.py,sha256=0wErYlxir5921agfFeV1xVjf29l9VNgGQvNlWOlj2Yc,23232
112
- pybiolib-1.1.1979.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
113
- pybiolib-1.1.1979.dist-info/METADATA,sha256=gaN82MLET8VrqRkqovA4ARsoe1iBCt5eWuA0YoalPaY,1508
114
- pybiolib-1.1.1979.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
115
- pybiolib-1.1.1979.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
116
- pybiolib-1.1.1979.dist-info/RECORD,,
112
+ pybiolib-1.1.1984.dist-info/LICENSE,sha256=F2h7gf8i0agDIeWoBPXDMYScvQOz02pAWkKhTGOHaaw,1067
113
+ pybiolib-1.1.1984.dist-info/METADATA,sha256=PO0Sif5QkYXg1P20p7306bX-CXn6-Mpee7epEsP-1Fo,1508
114
+ pybiolib-1.1.1984.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
115
+ pybiolib-1.1.1984.dist-info/entry_points.txt,sha256=p6DyaP_2kctxegTX23WBznnrDi4mz6gx04O5uKtRDXg,42
116
+ pybiolib-1.1.1984.dist-info/RECORD,,