Skip to content

Commit 8f9fd39

Browse files
committed
Upgrade/loosen dependencies and add invoke_batched parameter
1 parent 88d6d85 commit 8f9fd39

File tree

5 files changed

+2814
-1405
lines changed

5 files changed

+2814
-1405
lines changed

pyproject.toml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ dependencies = [
3232
'numpy>=1.21.2',
3333
'zarr>=2.5.0,<3',
3434
'numcodecs>=0.5.7,<0.16.0',
35-
'anndata>=0.7.8,<0.11.0',
35+
'anndata>=0.7.8',
3636
# scanpy < 1.10.3 does not support numpy >= 2.0.0 and does not
3737
# Reference: https://github.com/scverse/scanpy/pull/3115/files
3838
'scanpy>=1.10.2',
@@ -73,7 +73,7 @@ all = [
7373
'anywidget>=0.9.10',
7474
'uvicorn>=0.17.0',
7575
'ujson>=4.0.1',
76-
'starlette==0.14.0',
76+
'starlette>=0.14.0',
7777
'generate-tiff-offsets>=0.1.9',
7878
'kerchunk>=0.2.6',
7979
'fsspec',
@@ -87,7 +87,10 @@ all = [
8787
building = []
8888
testing = []
8989
linting = []
90-
notebook = []
90+
notebook = [
91+
'spatialdata>=0.3.0',
92+
'dask[dataframe]==2024.11.1',
93+
]
9194
demos = [
9295
"pulp==2.7.0",
9396
"snakemake",

src/vitessce/responses.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import ujson
2+
from starlette.responses import JSONResponse
3+
4+
# References:
5+
# - https://www.starlette.io/responses/#custom-json-serialization
6+
# - https://github.com/encode/starlette/releases/tag/0.14.1
7+
class UJSONResponse(JSONResponse):
8+
def render(self, content):
9+
return ujson.dumps(content, ensure_ascii=False).encode("utf-8")

src/vitessce/widget.py

Lines changed: 23 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,7 @@ def get_uid_str(uid):
233233
const remountOnUidChange = view.model.get('remount_on_uid_change');
234234
const storeUrls = view.model.get('store_urls');
235235
const invokeTimeout = view.model.get('invoke_timeout');
236+
const invokeBatched = view.model.get('invoke_batched');
236237
237238
const pageMode = view.model.get('page_mode');
238239
const pageEsm = view.model.get('page_esm');
@@ -319,23 +320,25 @@ def get_uid_str(uid):
319320
storeUrl,
320321
{
321322
async get(key) {
322-
return enqueue([storeUrl, key]);
323-
/*
324-
const [data, buffers] = await view.experimental.invoke("_zarr_get", [storeUrl, key], {
325-
signal: AbortSignal.timeout(invokeTimeout),
326-
});
327-
if (!data.success) return undefined;
328-
329-
if (key.includes("spatialdata_attrs") && key.endsWith("0") && !ArrayBuffer.isView(buffers[0].buffer)) {
330-
// For some reason, the Zarrita.js UnicodeStringArray does not seem to work with
331-
// ArrayBuffers (throws a TypeError), so here we convert to Uint8Array if needed.
332-
// This error is occurring specifically for the arr.getChunk call within the AnnDataSource._loadString function.
333-
// TODO: figure out a more long-term solution.
334-
return new Uint8Array(buffers[0].buffer);
335-
}
323+
if (invokeBatched) {
324+
return enqueue([storeUrl, key]);
325+
} else {
326+
// Do not submit zarr gets in batches. Instead, submit individually.
327+
const [data, buffers] = await view.experimental.invoke("_zarr_get", [storeUrl, key], {
328+
signal: AbortSignal.timeout(invokeTimeout),
329+
});
330+
if (!data.success) return undefined;
331+
332+
if (key.includes("spatialdata_attrs") && key.endsWith("0") && !ArrayBuffer.isView(buffers[0].buffer)) {
333+
// For some reason, the Zarrita.js UnicodeStringArray does not seem to work with
334+
// ArrayBuffers (throws a TypeError), so here we convert to Uint8Array if needed.
335+
// This error is occurring specifically for the arr.getChunk call within the AnnDataSource._loadString function.
336+
// TODO: figure out a more long-term solution.
337+
return new Uint8Array(buffers[0].buffer);
338+
}
336339
337-
return buffers[0].buffer;
338-
*/
340+
return buffers[0].buffer;
341+
}
339342
},
340343
}
341344
])),
@@ -603,10 +606,11 @@ class VitessceWidget(anywidget.AnyWidget):
603606
page_mode = Bool(False).tag(sync=True)
604607
page_esm = Unicode('').tag(sync=True)
605608
invoke_timeout = Int(300000).tag(sync=True)
609+
invoke_batched = Bool(True).tag(sync=True)
606610

607611
store_urls = List(trait=Unicode(''), default_value=[]).tag(sync=True)
608612

609-
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.5.11', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, page_mode=False, page_esm=None):
613+
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.5.11', js_dev_mode=False, custom_js_url='', plugins=None, remount_on_uid_change=True, prefer_local=True, invoke_timeout=300000, invoke_batched=True, page_mode=False, page_esm=None):
610614
"""
611615
Construct a new Vitessce widget.
612616
@@ -623,6 +627,7 @@ def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=
623627
:param bool remount_on_uid_change: Passed to the remountOnUidChange prop of the <Vitessce/> React component. By default, True.
624628
:param bool prefer_local: Should local data be preferred (only applies to `*_artifact` data objects)? By default, True.
625629
:param int invoke_timeout: The timeout in milliseconds for invoking Python functions from JavaScript. By default, 300000.
630+
:param bool invoke_batched: Should invocations (Zarr gets) be submitted in batch, or individually? By default, True.
626631
:param bool page_mode: Whether to render the <Vitessce/> component in grid-mode or page-mode. By default, False.
627632
:param str page_esm: The ES module string for the page component creation function. Optional.
628633
@@ -658,7 +663,7 @@ def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=
658663
js_package_version=js_package_version, js_dev_mode=js_dev_mode, custom_js_url=custom_js_url,
659664
plugin_esm=plugin_esm, remount_on_uid_change=remount_on_uid_change,
660665
page_mode=page_mode, page_esm=('' if page_esm is None else page_esm),
661-
invoke_timeout=invoke_timeout,
666+
invoke_timeout=invoke_timeout, invoke_batched=invoke_batched,
662667
uid=uid_str, store_urls=list(self._stores.keys())
663668
)
664669

src/vitessce/wrappers.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -390,8 +390,8 @@ def make_raster_routes(self, dataset_uid, obj_i):
390390
else:
391391
# TODO: Move imports back to top when this is factored out.
392392
from .routes import range_repsonse, JsonRoute, FileRoute
393+
from .responses import UJSONResponse
393394
from generate_tiff_offsets import get_offsets
394-
from starlette.responses import UJSONResponse
395395

396396
offsets = get_offsets(self._img_path)
397397

@@ -533,8 +533,8 @@ def make_raster_routes(self, dataset_uid, obj_i):
533533
else:
534534
# TODO: Move imports back to top when this is factored out.
535535
from .routes import range_repsonse, JsonRoute, FileRoute
536+
from .responses import UJSONResponse
536537
from generate_tiff_offsets import get_offsets
537-
from starlette.responses import UJSONResponse
538538

539539
offsets = get_offsets(self._img_path)
540540

@@ -666,8 +666,8 @@ def make_raster_routes(self, dataset_uid, obj_i):
666666
else:
667667
# TODO: Move imports back to top when this is factored out.
668668
from .routes import range_repsonse, JsonRoute, FileRoute
669+
from .responses import UJSONResponse
669670
from generate_tiff_offsets import get_offsets
670-
from starlette.responses import UJSONResponse
671671

672672
offsets = get_offsets(self._img_path)
673673

0 commit comments

Comments
 (0)