Skip to content

Commit 7514a1c

Browse files
committed
Version fix
2 parents 96c7c95 + b5fae09 commit 7514a1c

File tree

5 files changed

+966
-150
lines changed

5 files changed

+966
-150
lines changed

pyproject.toml

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
44

55
[project]
66
name = "vitessce"
7-
version = "3.6.1"
7+
version = "3.6.0"
88
authors = [
99
{ name="Mark Keller", email="mark_keller@hms.harvard.edu" },
1010
]
@@ -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',
@@ -64,16 +64,16 @@ docs = [
6464
'sqlalchemy==1.3.24',
6565
# nbconvert and jinja2 versions need to be pinned.
6666
# Reference: https://github.com/vitessce/vitessce-python/issues/152
67-
'nbconvert==5.6.1',
68-
'jinja2==3.0.3',
67+
'nbconvert>=6.2',
68+
'jinja2',
6969
]
7070
all = [
7171
'jupyter-server-proxy>=1.5.2',
7272
'oxc-py>=0.1.1',
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,12 @@ all = [
8787
building = []
8888
testing = []
8989
linting = []
90-
notebook = []
90+
notebook = [
91+
'spatialdata>=0.3.0',
92+
'dask[dataframe]==2024.11.1',
93+
'marimo',
94+
'starlette>=0.42.0',
95+
]
9196
demos = [
9297
"pulp==2.7.0",
9398
"snakemake",
@@ -112,9 +117,7 @@ dev = [
112117

113118
[tool.uv]
114119
default-groups = ["dev"]
115-
override-dependencies = [
116-
'starlette==0.14.0'
117-
]
120+
override-dependencies = []
118121

119122
[tool.hatch.build]
120123
exclude = [".github", "docs", "demos", "binder"]

src/vitessce/responses.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
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+
8+
9+
class UJSONResponse(JSONResponse):
10+
def render(self, content):
11+
return ujson.dumps(content, ensure_ascii=False).encode("utf-8")

src/vitessce/widget.py

Lines changed: 30 additions & 21 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
])),
@@ -413,7 +416,7 @@ def get_uid_str(uid):
413416
}
414417
415418
function VitessceWidget(props) {
416-
const { model } = props;
419+
const { model, styleContainer } = props;
417420
418421
const [config, setConfig] = React.useState(prependBaseUrl(model.get('config'), model.get('proxy'), model.get('has_host_name')));
419422
const [validateConfig, setValidateConfig] = React.useState(true);
@@ -477,7 +480,7 @@ def get_uid_str(uid):
477480
height, theme, config, onConfigChange, validateConfig,
478481
pluginViewTypes, pluginCoordinationTypes,
479482
pluginFileTypes,pluginJointFileTypes, pluginAsyncFunctions,
480-
remountOnUidChange, stores, pageMode,
483+
remountOnUidChange, stores, pageMode, styleContainer,
481484
};
482485
483486
return e('div', { ref: divRef, style: { height: height + 'px' } },
@@ -492,7 +495,10 @@ def get_uid_str(uid):
492495
}
493496
494497
const root = createRoot(view.el);
495-
root.render(e(VitessceWidget, { model: view.model }));
498+
// Marimo puts AnyWidgets in a Shadow Root, so we need to tell Emotion to
499+
// insert styles within the Shadow DOM.
500+
const styleContainer = view.el.getRootNode();
501+
root.render(e(VitessceWidget, { model: view.model, styleContainer }));
496502
497503
return () => {
498504
// Re-enable scrolling.
@@ -603,10 +609,11 @@ class VitessceWidget(anywidget.AnyWidget):
603609
page_mode = Bool(False).tag(sync=True)
604610
page_esm = Unicode('').tag(sync=True)
605611
invoke_timeout = Int(300000).tag(sync=True)
612+
invoke_batched = Bool(True).tag(sync=True)
606613

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

609-
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.5.12', 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):
616+
def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=False, js_package_version='3.5.12', 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):
610617
"""
611618
Construct a new Vitessce widget.
612619
@@ -623,6 +630,7 @@ def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=
623630
:param bool remount_on_uid_change: Passed to the remountOnUidChange prop of the <Vitessce/> React component. By default, True.
624631
:param bool prefer_local: Should local data be preferred (only applies to `*_artifact` data objects)? By default, True.
625632
:param int invoke_timeout: The timeout in milliseconds for invoking Python functions from JavaScript. By default, 300000.
633+
:param bool invoke_batched: Should invocations (Zarr gets) be submitted in batch, or individually? By default, True.
626634
:param bool page_mode: Whether to render the <Vitessce/> component in grid-mode or page-mode. By default, False.
627635
:param str page_esm: The ES module string for the page component creation function. Optional.
628636
@@ -658,7 +666,7 @@ def __init__(self, config, height=600, theme='auto', uid=None, port=None, proxy=
658666
js_package_version=js_package_version, js_dev_mode=js_dev_mode, custom_js_url=custom_js_url,
659667
plugin_esm=plugin_esm, remount_on_uid_change=remount_on_uid_change,
660668
page_mode=page_mode, page_esm=('' if page_esm is None else page_esm),
661-
invoke_timeout=invoke_timeout,
669+
invoke_timeout=invoke_timeout, invoke_batched=invoke_batched,
662670
uid=uid_str, store_urls=list(self._stores.keys())
663671
)
664672

@@ -763,6 +771,7 @@ def ipython_display(config, height=600, theme='auto', base_url=None, host_name=N
763771
"page_esm": ('' if page_esm is None else page_esm),
764772
"remount_on_uid_change": remount_on_uid_change,
765773
"invoke_timeout": 30000,
774+
"invoke_batched": False,
766775
"proxy": proxy,
767776
"has_host_name": host_name is not None,
768777
"height": height,

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)