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.
- {clouditia-1.7.0/clouditia.egg-info → clouditia-1.7.2}/PKG-INFO +1 -1
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/__init__.py +1 -1
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/client.py +54 -67
- {clouditia-1.7.0 → clouditia-1.7.2/clouditia.egg-info}/PKG-INFO +1 -1
- {clouditia-1.7.0 → clouditia-1.7.2}/pyproject.toml +1 -1
- {clouditia-1.7.0 → clouditia-1.7.2}/CHANGELOG.md +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/LICENSE +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/MANIFEST.in +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/README.md +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/exceptions.py +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/jobs.py +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/magic.py +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/py.typed +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia/results.py +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia.egg-info/SOURCES.txt +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia.egg-info/dependency_links.txt +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia.egg-info/requires.txt +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/clouditia.egg-info/top_level.txt +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/setup.cfg +0 -0
- {clouditia-1.7.0 → clouditia-1.7.2}/setup.py +0 -0
|
@@ -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
|
-
|
|
772
|
-
|
|
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
|
-
|
|
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
|
-
#
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
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
|
-
|
|
1123
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
1137
|
+
result = self.run(code, stream=False)
|
|
1138
1138
|
|
|
1139
|
-
|
|
1140
|
-
|
|
1139
|
+
if not result.success:
|
|
1140
|
+
raise ClouditiaError(f"Upload folder failed: {result.error}")
|
|
1141
1141
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1142
|
+
if show_progress:
|
|
1143
|
+
print(f"✅ Folder uploaded to {remote_path}")
|
|
1144
1144
|
|
|
1145
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1220
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
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
|
-
|
|
1249
|
-
|
|
1233
|
+
# Clean remote tar
|
|
1234
|
+
self.run(f'import os; os.remove("{remote_tar}")', stream=False)
|
|
1250
1235
|
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1260
|
-
|
|
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
|
-
|
|
1247
|
+
return True
|
|
1248
|
+
finally:
|
|
1249
|
+
os.unlink(tmp_path)
|
|
1263
1250
|
|
|
1264
1251
|
def list_files(
|
|
1265
1252
|
self,
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|