clouditia 1.7.0__tar.gz → 1.7.2__tar.gz

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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clouditia
3
- Version: 1.7.0
3
+ Version: 1.7.2
4
4
  Summary: Execute Python and Shell code on remote GPU sessions
5
5
  Author-email: Aina KIKI-SAGBE <support@clouditia.com>
6
6
  Maintainer-email: Aina KIKI-SAGBE <support@clouditia.com>
@@ -15,7 +15,7 @@ Basic Usage:
15
15
  For more examples, see: https://clouditia.com/docs
16
16
  """
17
17
 
18
- __version__ = "1.7.0"
18
+ __version__ = "1.7.2"
19
19
  __author__ = "Aina KIKI-SAGBE"
20
20
  __email__ = "support@clouditia.com"
21
21
 
@@ -767,9 +767,11 @@ print(base64.b64encode(pickle.dumps(_tmp_val)).decode())
767
767
  # ==================== FILE TRANSFER METHODS ====================
768
768
 
769
769
  def _get_upload_config(self) -> dict:
770
- """Get upload config from server (max size, chunk size). Cached."""
771
- if hasattr(self, '_upload_config_cache'):
772
- return self._upload_config_cache
770
+ """Get upload config from server (max size, chunk size). Cached 60s."""
771
+ now = time.time()
772
+ if hasattr(self, '_upload_config_cache') and hasattr(self, '_upload_config_ts'):
773
+ if now - self._upload_config_ts < 60:
774
+ return self._upload_config_cache
773
775
  try:
774
776
  response = requests.get(
775
777
  f"{self.base_url}/api/upload-config/",
@@ -782,12 +784,12 @@ print(base64.b64encode(pickle.dumps(_tmp_val)).decode())
782
784
  'max_upload_size_mb': data.get('max_upload_size_mb', 100),
783
785
  'chunk_size_bytes': data.get('chunk_size_bytes', 3 * 1024 * 1024),
784
786
  }
787
+ self._upload_config_ts = now
785
788
  return self._upload_config_cache
786
789
  except Exception:
787
790
  pass
788
791
  # Defaults if API unavailable
789
- self._upload_config_cache = {'max_upload_size_mb': 100, 'chunk_size_bytes': 3 * 1024 * 1024}
790
- return self._upload_config_cache
792
+ return {'max_upload_size_mb': 100, 'chunk_size_bytes': 3 * 1024 * 1024}
791
793
 
792
794
  def upload(
793
795
  self,
@@ -1107,42 +1109,42 @@ print("__FILEDATA_END__")
1107
1109
  tar.add(local_path, arcname=os.path.basename(local_path), filter=filter_func)
1108
1110
 
1109
1111
  tar_data = tar_buffer.getvalue()
1110
- tar_b64 = base64.b64encode(tar_data).decode()
1111
1112
 
1112
1113
  if show_progress:
1113
1114
  print(f"📤 Uploading {self._format_size(len(tar_data))}...")
1114
1115
 
1115
- # Transfer and extract on remote
1116
- code = f'''
1117
- import base64
1118
- import tarfile
1119
- import io
1120
- import os
1116
+ # Save tar to temp file and use upload() with chunking support
1117
+ import tempfile
1118
+ with tempfile.NamedTemporaryFile(suffix='.tar.gz', delete=False) as tmp:
1119
+ tmp.write(tar_data)
1120
+ tmp_path = tmp.name
1121
1121
 
1122
- # Decode tar data
1123
- tar_data = base64.b64decode("{tar_b64}")
1122
+ try:
1123
+ # Upload tar.gz via chunked upload
1124
+ remote_tar = f"/tmp/_clouditia_upload_{os.path.basename(local_path)}.tar.gz"
1125
+ self.upload(tmp_path, remote_tar, show_progress=False)
1124
1126
 
1125
- # Create destination directory
1127
+ # Extract on remote
1128
+ code = f'''
1129
+ import tarfile, os
1126
1130
  os.makedirs("{remote_path}", exist_ok=True)
1127
-
1128
- # Extract
1129
- tar_buffer = io.BytesIO(tar_data)
1130
- with tarfile.open(fileobj=tar_buffer, mode='r:gz') as tar:
1131
+ with tarfile.open("{remote_tar}", "r:gz") as tar:
1131
1132
  tar.extractall(path="{remote_path}")
1132
-
1133
- # Count files
1133
+ os.remove("{remote_tar}")
1134
1134
  file_count = sum(1 for root, dirs, files in os.walk("{remote_path}") for f in files)
1135
1135
  print(f"Extracted {{file_count}} files to {remote_path}")
1136
1136
  '''
1137
- result = self.run(code, stream=False)
1137
+ result = self.run(code, stream=False)
1138
1138
 
1139
- if not result.success:
1140
- raise ClouditiaError(f"Upload folder failed: {result.error}")
1139
+ if not result.success:
1140
+ raise ClouditiaError(f"Upload folder failed: {result.error}")
1141
1141
 
1142
- if show_progress:
1143
- print(f"✅ Folder uploaded to {remote_path}")
1142
+ if show_progress:
1143
+ print(f"✅ Folder uploaded to {remote_path}")
1144
1144
 
1145
- return True
1145
+ return True
1146
+ finally:
1147
+ os.unlink(tmp_path)
1146
1148
 
1147
1149
  def download_folder(
1148
1150
  self,
@@ -1184,17 +1186,13 @@ print(f"Extracted {{file_count}} files to {remote_path}")
1184
1186
  # Build exclude filter for Python
1185
1187
  exclude_patterns = repr(exclude)
1186
1188
 
1187
- # Compress on remote and get base64
1189
+ # Compress on remote into a tar.gz file
1190
+ remote_tar = f"/tmp/_clouditia_download_{os.path.basename(remote_path)}.tar.gz"
1188
1191
  code = f'''
1189
- import base64
1190
- import tarfile
1191
- import io
1192
- import os
1193
- import fnmatch
1192
+ import tarfile, os, fnmatch
1194
1193
 
1195
1194
  if not os.path.exists("{remote_path}"):
1196
1195
  raise FileNotFoundError("Folder not found: {remote_path}")
1197
-
1198
1196
  if not os.path.isdir("{remote_path}"):
1199
1197
  raise NotADirectoryError("Path is not a directory. Use download() instead.")
1200
1198
 
@@ -1211,55 +1209,44 @@ def filter_func(tarinfo):
1211
1209
  return None
1212
1210
  return tarinfo
1213
1211
 
1214
- # Create tar.gz in memory
1215
- tar_buffer = io.BytesIO()
1216
- with tarfile.open(fileobj=tar_buffer, mode='w:gz') as tar:
1212
+ with tarfile.open("{remote_tar}", "w:gz") as tar:
1217
1213
  tar.add("{remote_path}", arcname=os.path.basename("{remote_path}"), filter=filter_func)
1218
1214
 
1219
- tar_data = tar_buffer.getvalue()
1220
- tar_b64 = base64.b64encode(tar_data).decode()
1221
- print(f"Compressed size: {{len(tar_data)}} bytes")
1222
- print("__FOLDERDATA_START__")
1223
- print(tar_b64)
1224
- print("__FOLDERDATA_END__")
1215
+ size = os.path.getsize("{remote_tar}")
1216
+ print(f"Compressed: {{size}} bytes")
1225
1217
  '''
1226
1218
  result = self.run(code, stream=False)
1227
-
1228
1219
  if not result.success:
1229
1220
  raise ClouditiaError(f"Download folder failed: {result.error}")
1230
1221
 
1231
- # Extract base64 data from output
1232
- output = result.output or ""
1233
- if "__FOLDERDATA_START__" not in output or "__FOLDERDATA_END__" not in output:
1234
- raise ClouditiaError("No data received from remote")
1235
-
1236
1222
  if show_progress:
1237
1223
  print(f"📥 Downloading...")
1238
1224
 
1239
- # Decode and extract locally
1225
+ # Download tar.gz via chunked download
1226
+ import tempfile
1227
+ with tempfile.NamedTemporaryFile(suffix='.tar.gz', delete=False) as tmp:
1228
+ tmp_path = tmp.name
1229
+
1240
1230
  try:
1241
- start = output.index("__FOLDERDATA_START__") + len("__FOLDERDATA_START__")
1242
- end = output.index("__FOLDERDATA_END__")
1243
- tar_b64 = output[start:end].strip()
1244
- tar_data = base64.b64decode(tar_b64)
1245
- except Exception as e:
1246
- raise ClouditiaError(f"Failed to decode folder data: {e}")
1231
+ self.download(remote_tar, tmp_path, show_progress=False)
1247
1232
 
1248
- # Create local directory
1249
- local_path.mkdir(parents=True, exist_ok=True)
1233
+ # Clean remote tar
1234
+ self.run(f'import os; os.remove("{remote_tar}")', stream=False)
1250
1235
 
1251
- # Extract
1252
- tar_buffer = io.BytesIO(tar_data)
1253
- with tarfile.open(fileobj=tar_buffer, mode='r:gz') as tar:
1254
- tar.extractall(path=local_path)
1236
+ # Extract locally
1237
+ local_path.mkdir(parents=True, exist_ok=True)
1238
+ with tarfile.open(tmp_path, mode='r:gz') as tar:
1239
+ tar.extractall(path=local_path)
1255
1240
 
1256
- # Count files
1257
- file_count = sum(1 for root, dirs, files in os.walk(local_path) for f in files)
1241
+ file_count = sum(1 for root, dirs, files in os.walk(local_path) for f in files)
1258
1242
 
1259
- if show_progress:
1260
- print(f"✅ Downloaded to {local_path} ({file_count} files, {self._format_size(len(tar_data))})")
1243
+ if show_progress:
1244
+ tar_size = os.path.getsize(tmp_path)
1245
+ print(f"✅ Downloaded to {local_path} ({file_count} files, {self._format_size(tar_size)})")
1261
1246
 
1262
- return True
1247
+ return True
1248
+ finally:
1249
+ os.unlink(tmp_path)
1263
1250
 
1264
1251
  def list_files(
1265
1252
  self,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: clouditia
3
- Version: 1.7.0
3
+ Version: 1.7.2
4
4
  Summary: Execute Python and Shell code on remote GPU sessions
5
5
  Author-email: Aina KIKI-SAGBE <support@clouditia.com>
6
6
  Maintainer-email: Aina KIKI-SAGBE <support@clouditia.com>
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "clouditia"
7
- version = "1.7.0"
7
+ version = "1.7.2"
8
8
  description = "Execute Python and Shell code on remote GPU sessions"
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes