malva-client 0.3.2__tar.gz → 0.3.3__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.
- {malva_client-0.3.2/malva_client.egg-info → malva_client-0.3.3}/PKG-INFO +1 -1
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/__init__.py +1 -1
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/client.py +36 -6
- {malva_client-0.3.2 → malva_client-0.3.3/malva_client.egg-info}/PKG-INFO +1 -1
- {malva_client-0.3.2 → malva_client-0.3.3}/pyproject.toml +1 -1
- {malva_client-0.3.2 → malva_client-0.3.3}/CHANGELOG.md +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/LICENSE +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/MANIFEST.in +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/README.md +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/auth.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/cli.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/config.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/exceptions.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/models.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/storage.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client/tools.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client.egg-info/SOURCES.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client.egg-info/dependency_links.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client.egg-info/entry_points.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client.egg-info/requires.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/malva_client.egg-info/top_level.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/requirements.txt +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/setup.cfg +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/tests/test_client.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/tests/test_config.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/tests/test_exceptions.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/tests/test_models.py +0 -0
- {malva_client-0.3.2 → malva_client-0.3.3}/tests/test_storage.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: malva-client
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Python client for Malva Index
|
|
5
5
|
Author-email: Daniel León-Periñán <daniel.leonperinan@mdc-berlin.de>, Nikos Karaiskos <nikolaos.karaiskos@mdc-berlin.de>
|
|
6
6
|
Maintainer-email: Daniel León-Periñán <daniel.leonperinan@mdc-berlin.de>, Nikos Karaiskos <nikolaos.karaiskos@mdc-berlin.de>
|
|
@@ -366,13 +366,35 @@ class MalvaClient:
|
|
|
366
366
|
payload['unstranded_mode'] = True
|
|
367
367
|
return payload
|
|
368
368
|
|
|
369
|
+
def _get_job_status_lightweight(self, job_id: str) -> Dict[str, Any]:
|
|
370
|
+
"""Fetch job status without forcing the server to return result data."""
|
|
371
|
+
try:
|
|
372
|
+
return self._request('GET', f'/search/{job_id}/status')
|
|
373
|
+
except MalvaAPIError as exc:
|
|
374
|
+
if self._is_not_found_error(exc):
|
|
375
|
+
return self._request('GET', f'/search/{job_id}')
|
|
376
|
+
raise
|
|
377
|
+
|
|
378
|
+
@staticmethod
|
|
379
|
+
def _adaptive_poll_delay(elapsed: float, poll_interval: int) -> float:
|
|
380
|
+
max_delay = max(float(poll_interval), 0.0)
|
|
381
|
+
if max_delay <= 0:
|
|
382
|
+
return 0.0
|
|
383
|
+
if elapsed < 2:
|
|
384
|
+
return min(max_delay, 0.2)
|
|
385
|
+
if elapsed < 5:
|
|
386
|
+
return min(max_delay, 0.5)
|
|
387
|
+
if elapsed < 15:
|
|
388
|
+
return min(max_delay, 1.0)
|
|
389
|
+
return max_delay
|
|
390
|
+
|
|
369
391
|
def _poll_until_complete(self, job_id: str, poll_interval: int,
|
|
370
392
|
max_wait: int, context: str = "search") -> SearchResult:
|
|
371
393
|
"""Poll GET /search/<job_id> until completed, return lazy SearchResult."""
|
|
372
394
|
start_time = time.time()
|
|
373
395
|
while time.time() - start_time < max_wait:
|
|
374
396
|
try:
|
|
375
|
-
resp = self.
|
|
397
|
+
resp = self._get_job_status_lightweight(job_id)
|
|
376
398
|
status = resp.get('status')
|
|
377
399
|
logger.info(f"{context} status: {status}")
|
|
378
400
|
if status == 'completed':
|
|
@@ -385,7 +407,9 @@ class MalvaClient:
|
|
|
385
407
|
pass # job not yet visible, keep polling
|
|
386
408
|
else:
|
|
387
409
|
raise
|
|
388
|
-
time.
|
|
410
|
+
delay = self._adaptive_poll_delay(time.time() - start_time, poll_interval)
|
|
411
|
+
if delay > 0:
|
|
412
|
+
time.sleep(delay)
|
|
389
413
|
raise MalvaAPIError(f"{context} timed out after {max_wait} seconds")
|
|
390
414
|
|
|
391
415
|
def search(self, query: str,
|
|
@@ -837,7 +861,10 @@ class MalvaClient:
|
|
|
837
861
|
sample_ids: Optional[List[int]],
|
|
838
862
|
include_barcodes: bool,
|
|
839
863
|
include_sample_metadata: bool) -> CellExpressionMatrixResult:
|
|
840
|
-
|
|
864
|
+
params = {}
|
|
865
|
+
if sample_ids:
|
|
866
|
+
params['sample_ids'] = ','.join(str(s) for s in sample_ids)
|
|
867
|
+
response = self._request_raw('GET', f'/search/{job_id}/global-cell-ids', params=params)
|
|
841
868
|
decoded = msgpack.unpackb(response.content, raw=False, strict_map_key=False)
|
|
842
869
|
cells = np.frombuffer(decoded.get('c', b''), dtype=np.int64)
|
|
843
870
|
samples = np.frombuffer(decoded.get('s', b''), dtype=np.int64)
|
|
@@ -1600,14 +1627,14 @@ class MalvaClient:
|
|
|
1600
1627
|
from malva_client.storage import save_job_status
|
|
1601
1628
|
|
|
1602
1629
|
try:
|
|
1603
|
-
response = self.
|
|
1630
|
+
response = self._get_job_status_lightweight(job_id)
|
|
1604
1631
|
|
|
1605
1632
|
# Update local storage
|
|
1606
1633
|
save_job_status(
|
|
1607
1634
|
job_id=job_id,
|
|
1608
1635
|
status=response.get('status', 'unknown'),
|
|
1609
1636
|
server_url=self.base_url,
|
|
1610
|
-
results_data=
|
|
1637
|
+
results_data=None,
|
|
1611
1638
|
error_message=response.get('error') if response.get('status') == 'error' else None
|
|
1612
1639
|
)
|
|
1613
1640
|
|
|
@@ -1718,6 +1745,7 @@ class MalvaClient:
|
|
|
1718
1745
|
start_time = time.time()
|
|
1719
1746
|
|
|
1720
1747
|
while time.time() - start_time < max_wait:
|
|
1748
|
+
elapsed = time.time() - start_time
|
|
1721
1749
|
status_response = self.get_job_status(job_id)
|
|
1722
1750
|
status = status_response.get('status')
|
|
1723
1751
|
|
|
@@ -1728,7 +1756,9 @@ class MalvaClient:
|
|
|
1728
1756
|
raise SearchError(f"Job {job_id} failed: {error_msg}")
|
|
1729
1757
|
elif status in ['pending', 'running']:
|
|
1730
1758
|
logger.info(f"Job {job_id} status: {status}")
|
|
1731
|
-
|
|
1759
|
+
delay = self._adaptive_poll_delay(elapsed, poll_interval)
|
|
1760
|
+
if delay > 0:
|
|
1761
|
+
time.sleep(delay)
|
|
1732
1762
|
else:
|
|
1733
1763
|
raise SearchError(f"Job {job_id} has unexpected status: {status}")
|
|
1734
1764
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: malva-client
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.3
|
|
4
4
|
Summary: Python client for Malva Index
|
|
5
5
|
Author-email: Daniel León-Periñán <daniel.leonperinan@mdc-berlin.de>, Nikos Karaiskos <nikolaos.karaiskos@mdc-berlin.de>
|
|
6
6
|
Maintainer-email: Daniel León-Periñán <daniel.leonperinan@mdc-berlin.de>, Nikos Karaiskos <nikolaos.karaiskos@mdc-berlin.de>
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|