arrayview 0.35.2__py3-none-any.whl → 0.36.0__py3-none-any.whl
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.
- arrayview/_launcher.py +44 -0
- arrayview/_routes_loading.py +7 -3
- arrayview/_routes_query.py +8 -0
- arrayview/_session.py +5 -0
- arrayview/_viewer.html +64 -15
- arrayview/_vscode_extension.py +46 -2
- arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.35.2.dist-info → arrayview-0.36.0.dist-info}/METADATA +1 -1
- {arrayview-0.35.2.dist-info → arrayview-0.36.0.dist-info}/RECORD +12 -12
- {arrayview-0.35.2.dist-info → arrayview-0.36.0.dist-info}/WHEEL +0 -0
- {arrayview-0.35.2.dist-info → arrayview-0.36.0.dist-info}/entry_points.txt +0 -0
- {arrayview-0.35.2.dist-info → arrayview-0.36.0.dist-info}/licenses/LICENSE +0 -0
arrayview/_launcher.py
CHANGED
|
@@ -2590,6 +2590,11 @@ _PERSIST_DAEMON_CONNECT_TIMEOUT_SECONDS = float(
|
|
|
2590
2590
|
_PERSIST_DAEMON_IDLE_SECONDS = float(
|
|
2591
2591
|
os.environ.get("ARRAYVIEW_PERSIST_IDLE_SECONDS", "1800")
|
|
2592
2592
|
)
|
|
2593
|
+
# How long a daemon whose initial load failed keeps serving so the opener can
|
|
2594
|
+
# read the reason from /metadata/<sid> before the port is released.
|
|
2595
|
+
_FAILED_LOAD_EXIT_GRACE_SECONDS = float(
|
|
2596
|
+
os.environ.get("ARRAYVIEW_FAILED_LOAD_EXIT_GRACE_SECONDS", "30")
|
|
2597
|
+
)
|
|
2593
2598
|
|
|
2594
2599
|
|
|
2595
2600
|
def _join_query_values(values: _CSVValues) -> str:
|
|
@@ -4169,6 +4174,7 @@ def _serve_daemon(
|
|
|
4169
4174
|
owner="persistent" if persist else "transient",
|
|
4170
4175
|
)
|
|
4171
4176
|
# Register sid as pending so /metadata can poll while data loads.
|
|
4177
|
+
_initial_load_failed = threading.Event()
|
|
4172
4178
|
_session_mod.PENDING_SESSIONS.add(sid)
|
|
4173
4179
|
_pending_event = threading.Event()
|
|
4174
4180
|
_session_mod.PENDING_SESSION_EVENTS[sid] = _pending_event
|
|
@@ -4349,6 +4355,18 @@ def _serve_daemon(
|
|
|
4349
4355
|
sid_tag=sid_tag,
|
|
4350
4356
|
error_type=type(exc).__name__,
|
|
4351
4357
|
)
|
|
4358
|
+
# This runs on a daemon thread, so re-raising only kills the thread
|
|
4359
|
+
# and writes to a stderr nobody reads. Record why the sid will never
|
|
4360
|
+
# become ready so /metadata can report it instead of returning 404
|
|
4361
|
+
# until the opener gives up.
|
|
4362
|
+
_session_mod.FAILED_PENDING_SESSIONS[sid] = (
|
|
4363
|
+
str(exc) or type(exc).__name__
|
|
4364
|
+
)
|
|
4365
|
+
_vprint(
|
|
4366
|
+
f"[ArrayView] Failed to load {filepath}: {exc}",
|
|
4367
|
+
flush=True,
|
|
4368
|
+
)
|
|
4369
|
+
_initial_load_failed.set()
|
|
4352
4370
|
raise
|
|
4353
4371
|
finally:
|
|
4354
4372
|
_session_mod.PENDING_SESSIONS.discard(sid)
|
|
@@ -4357,6 +4375,32 @@ def _serve_daemon(
|
|
|
4357
4375
|
|
|
4358
4376
|
threading.Thread(target=_load, daemon=True).start()
|
|
4359
4377
|
|
|
4378
|
+
def _exit_if_initial_load_failed() -> None:
|
|
4379
|
+
"""Release the port when the file this daemon exists to serve won't load.
|
|
4380
|
+
|
|
4381
|
+
uvicorn starts before the load finishes, so a failed load otherwise
|
|
4382
|
+
leaves a server with no session holding the port until the connect
|
|
4383
|
+
timeout expires minutes later — and answering /ping the whole time. The
|
|
4384
|
+
grace period is only so the opener can read the failure from
|
|
4385
|
+
/metadata/<sid> before the port goes away.
|
|
4386
|
+
"""
|
|
4387
|
+
_initial_load_failed.wait()
|
|
4388
|
+
time.sleep(_FAILED_LOAD_EXIT_GRACE_SECONDS)
|
|
4389
|
+
if _session_mod.SESSIONS or _session_mod.VIEWER_SOCKETS:
|
|
4390
|
+
return # something else is using this server; leave it alone
|
|
4391
|
+
_trace_launch_event(
|
|
4392
|
+
"daemon.exiting",
|
|
4393
|
+
reason="initial_load_failed",
|
|
4394
|
+
instance_tag=_launch_trace_tag(record.instance_id),
|
|
4395
|
+
)
|
|
4396
|
+
try:
|
|
4397
|
+
registry.remove(record.instance_id)
|
|
4398
|
+
except Exception:
|
|
4399
|
+
pass
|
|
4400
|
+
os._exit(0)
|
|
4401
|
+
|
|
4402
|
+
threading.Thread(target=_exit_if_initial_load_failed, daemon=True).start()
|
|
4403
|
+
|
|
4360
4404
|
if persist:
|
|
4361
4405
|
_wait_for_viewer_close(
|
|
4362
4406
|
idle_seconds=_PERSIST_DAEMON_IDLE_SECONDS,
|
arrayview/_routes_loading.py
CHANGED
|
@@ -18,6 +18,7 @@ from arrayview._lifecycle import (
|
|
|
18
18
|
)
|
|
19
19
|
from arrayview._session import (
|
|
20
20
|
CANCELLED_PENDING_SESSIONS,
|
|
21
|
+
FAILED_PENDING_SESSIONS,
|
|
21
22
|
PENDING_SESSION_EVENTS,
|
|
22
23
|
PENDING_SESSIONS,
|
|
23
24
|
SESSIONS,
|
|
@@ -263,6 +264,7 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
263
264
|
# the real Session instead of seeing a transient 404.
|
|
264
265
|
sid = requested_sid or uuid.uuid4().hex
|
|
265
266
|
pending_event = threading.Event()
|
|
267
|
+
FAILED_PENDING_SESSIONS.pop(sid, None)
|
|
266
268
|
PENDING_SESSIONS.add(sid)
|
|
267
269
|
PENDING_SESSION_EVENTS[sid] = pending_event
|
|
268
270
|
signature_before_load = file_signature(abs_path)
|
|
@@ -293,12 +295,14 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
293
295
|
]
|
|
294
296
|
commit_pending_session(sid, session)
|
|
295
297
|
except Exception as exc:
|
|
296
|
-
# Keep the server alive and
|
|
297
|
-
#
|
|
298
|
-
#
|
|
298
|
+
# Keep the server alive, and record why this sid will never
|
|
299
|
+
# become ready. Without the record the opener cannot tell a
|
|
300
|
+
# failed load from a slow one and burns its whole deadline
|
|
301
|
+
# on a file that raised immediately.
|
|
299
302
|
import traceback
|
|
300
303
|
|
|
301
304
|
traceback.print_exc()
|
|
305
|
+
FAILED_PENDING_SESSIONS[sid] = str(exc) or exc.__class__.__name__
|
|
302
306
|
finally:
|
|
303
307
|
PENDING_SESSIONS.discard(sid)
|
|
304
308
|
CANCELLED_PENDING_SESSIONS.discard(sid)
|
arrayview/_routes_query.py
CHANGED
|
@@ -211,6 +211,14 @@ def register_query_routes(app, *, get_session_or_404, pil_image, pil_imageops) -
|
|
|
211
211
|
# request; the opener retries until the pending Session is published.
|
|
212
212
|
if sid in _session_mod.PENDING_SESSIONS:
|
|
213
213
|
return Response(status_code=404, headers={"Retry-After": "1"})
|
|
214
|
+
# A load that raised is terminal. Say so with a distinct status and the
|
|
215
|
+
# real reason, so the caller stops polling and can show the user why
|
|
216
|
+
# this file will never open instead of waiting out its deadline.
|
|
217
|
+
load_error = _session_mod.FAILED_PENDING_SESSIONS.get(sid)
|
|
218
|
+
if load_error is not None:
|
|
219
|
+
return Response(
|
|
220
|
+
status_code=422, content=load_error.encode(), media_type="text/plain"
|
|
221
|
+
)
|
|
214
222
|
session = await wait_for_session_ready(sid)
|
|
215
223
|
if not session:
|
|
216
224
|
return Response(status_code=404)
|
arrayview/_session.py
CHANGED
|
@@ -41,6 +41,10 @@ _window_process = None
|
|
|
41
41
|
PENDING_SESSIONS: set = set() # sids whose data is still loading in a background thread
|
|
42
42
|
PENDING_SESSION_EVENTS: dict[str, threading.Event] = {}
|
|
43
43
|
CANCELLED_PENDING_SESSIONS: set[str] = set()
|
|
44
|
+
# sid -> why its background load failed. A load that raises must be reportable:
|
|
45
|
+
# without this the opener cannot tell "still loading" from "will never load" and
|
|
46
|
+
# waits out its whole deadline on a file that failed in the first second.
|
|
47
|
+
FAILED_PENDING_SESSIONS: dict[str, str] = {}
|
|
44
48
|
|
|
45
49
|
|
|
46
50
|
def file_signature(filepath: str):
|
|
@@ -575,6 +579,7 @@ __all__ = [
|
|
|
575
579
|
"_window_process",
|
|
576
580
|
"PENDING_SESSIONS",
|
|
577
581
|
"PENDING_SESSION_EVENTS",
|
|
582
|
+
"FAILED_PENDING_SESSIONS",
|
|
578
583
|
"wait_for_session_ready",
|
|
579
584
|
# Render thread pool
|
|
580
585
|
"_RENDER_QUEUE",
|
arrayview/_viewer.html
CHANGED
|
@@ -9278,7 +9278,20 @@
|
|
|
9278
9278
|
function formatValueGroup(values, options = {}) {
|
|
9279
9279
|
const finite = (Array.isArray(values) ? values : [values]).filter(Number.isFinite);
|
|
9280
9280
|
const cap = Math.max(0, Math.min(8, Math.trunc(options.maxDecimals ?? 7)));
|
|
9281
|
-
|
|
9281
|
+
// Decimals worth showing depend on magnitude. Two was applied at
|
|
9282
|
+
// every scale, so a range topping out near 1890 read as "1890.04"
|
|
9283
|
+
// when the hundredths carry no information. The floor is only ever
|
|
9284
|
+
// lowered for large values, never raised, so small ranges keep the
|
|
9285
|
+
// precision they had. The search below can still add decimals when
|
|
9286
|
+
// values would otherwise collide.
|
|
9287
|
+
const _defaultMinDecimals = (vals) => {
|
|
9288
|
+
const m = Math.max(...vals.filter(Number.isFinite).map(v => Math.abs(v)));
|
|
9289
|
+
if (!(m > 0) || !Number.isFinite(m)) return 2;
|
|
9290
|
+
return Math.max(0, Math.min(2, 3 - Math.floor(Math.log10(m))));
|
|
9291
|
+
};
|
|
9292
|
+
const minDecimals = Math.max(0, Math.min(cap, Math.trunc(
|
|
9293
|
+
options.minDecimals ?? _defaultMinDecimals(finite)
|
|
9294
|
+
)));
|
|
9282
9295
|
const ordinaryLo = options.ordinaryLo ?? 1e-4;
|
|
9283
9296
|
const ordinaryHi = options.ordinaryHi ?? 1e6;
|
|
9284
9297
|
const fallback = {
|
|
@@ -14242,6 +14255,41 @@
|
|
|
14242
14255
|
|
|
14243
14256
|
/* ── JS: Initialization and Metadata Fetch ────────────────── */
|
|
14244
14257
|
|
|
14258
|
+
// The backend serves this page as soon as its port is up, which can be
|
|
14259
|
+
// seconds before a large array has finished loading. While the session
|
|
14260
|
+
// is still loading /metadata answers 404 with a Retry-After header; an
|
|
14261
|
+
// unknown or released sid answers 404 without one, and a load that
|
|
14262
|
+
// failed answers 422 with the reason. Keep waiting only for the first.
|
|
14263
|
+
async function fetchMetadataWithRetry(sid, timeoutMs = 180000) {
|
|
14264
|
+
const deadline = Date.now() + timeoutMs;
|
|
14265
|
+
for (;;) {
|
|
14266
|
+
const res = await proxyFetch(`/metadata/${sid}`);
|
|
14267
|
+
if (res.ok) return { data: await res.json() };
|
|
14268
|
+
if (res.status === 422) {
|
|
14269
|
+
let reason = '';
|
|
14270
|
+
try { reason = (await res.text()).trim(); } catch (_e) {}
|
|
14271
|
+
return { error: reason || 'This file could not be loaded.', status: 422 };
|
|
14272
|
+
}
|
|
14273
|
+
const pending = res.status === 404 && res.headers.get('Retry-After');
|
|
14274
|
+
if (!pending || Date.now() >= deadline) {
|
|
14275
|
+
return { error: null, status: res.status };
|
|
14276
|
+
}
|
|
14277
|
+
await new Promise(r => setTimeout(r, 300));
|
|
14278
|
+
}
|
|
14279
|
+
}
|
|
14280
|
+
|
|
14281
|
+
function showMetadataError(result) {
|
|
14282
|
+
const msg = result.error
|
|
14283
|
+
? result.error
|
|
14284
|
+
: (result.status === 404
|
|
14285
|
+
? 'Session not found or expired.'
|
|
14286
|
+
: `Server error ${result.status} — check Python console for details.`);
|
|
14287
|
+
document.getElementById('loading-overlay').innerHTML =
|
|
14288
|
+
`<div style="color:#c55;font-size:16px;font-family:monospace;max-width:60ch;text-align:center;line-height:1.5;padding:0 2em">${
|
|
14289
|
+
msg.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>')
|
|
14290
|
+
}</div>`;
|
|
14291
|
+
}
|
|
14292
|
+
|
|
14245
14293
|
async function init() {
|
|
14246
14294
|
// Loading spinner is in static HTML — body.av-loading set by server template.
|
|
14247
14295
|
if (!sid) { hideLoadingOverlay(); drawPlasmaDemo(); return; }
|
|
@@ -14260,26 +14308,24 @@
|
|
|
14260
14308
|
);
|
|
14261
14309
|
data = await Promise.race([_metadataFromWs, httpFallback]);
|
|
14262
14310
|
if (!data) {
|
|
14263
|
-
// Both failed —
|
|
14264
|
-
const
|
|
14265
|
-
if (!
|
|
14266
|
-
reportParent('metadata-http-error', { status:
|
|
14267
|
-
|
|
14268
|
-
document.getElementById('loading-overlay').innerHTML = `<div style="color:#c55;font-size:18px;font-family:monospace">${msg}</div>`;
|
|
14311
|
+
// Both failed — wait out a still-loading session.
|
|
14312
|
+
const result = await fetchMetadataWithRetry(sid);
|
|
14313
|
+
if (!result.data) {
|
|
14314
|
+
reportParent('metadata-http-error', { status: result.status, sid });
|
|
14315
|
+
showMetadataError(result);
|
|
14269
14316
|
return;
|
|
14270
14317
|
}
|
|
14271
|
-
data =
|
|
14318
|
+
data = result.data;
|
|
14272
14319
|
}
|
|
14273
14320
|
} else {
|
|
14274
14321
|
// HTTP transport mode (VS Code) — use traditional fetch
|
|
14275
|
-
const
|
|
14276
|
-
if (!
|
|
14277
|
-
reportParent('metadata-http-error', { status:
|
|
14278
|
-
|
|
14279
|
-
document.getElementById('loading-overlay').innerHTML = `<div style="color:#c55;font-size:18px;font-family:monospace">${msg}</div>`;
|
|
14322
|
+
const result = await fetchMetadataWithRetry(sid);
|
|
14323
|
+
if (!result.data) {
|
|
14324
|
+
reportParent('metadata-http-error', { status: result.status, sid });
|
|
14325
|
+
showMetadataError(result);
|
|
14280
14326
|
return;
|
|
14281
14327
|
}
|
|
14282
|
-
data =
|
|
14328
|
+
data = result.data;
|
|
14283
14329
|
}
|
|
14284
14330
|
|
|
14285
14331
|
await _loadOverlayLabelValues();
|
|
@@ -35919,9 +35965,12 @@
|
|
|
35919
35965
|
return `${x.toFixed(1)},${y.toFixed(1)}`;
|
|
35920
35966
|
}).join(' ');
|
|
35921
35967
|
const distLabel = distance.toFixed(1) + ' px';
|
|
35968
|
+
// Share the colorbar's formatter so the same value does not read
|
|
35969
|
+
// differently here than it does on the colorbar.
|
|
35970
|
+
const _lpFmt = formatValueGroup([vMin, vMax]);
|
|
35922
35971
|
const fmtVal = v => {
|
|
35923
35972
|
if (v === null || !isFinite(v)) return '?';
|
|
35924
|
-
return
|
|
35973
|
+
return _lpFmt.format(v);
|
|
35925
35974
|
};
|
|
35926
35975
|
_lineProfileOverlay.innerHTML = `
|
|
35927
35976
|
<svg width="${W}" height="${H}" xmlns="http://www.w3.org/2000/svg">
|
arrayview/_vscode_extension.py
CHANGED
|
@@ -54,7 +54,7 @@ _VSCODE_EXT_INSTALLED = False # cached so we only check once per process
|
|
|
54
54
|
_VSCODE_EXT_FRESH_INSTALL = False # True if we just installed it this session
|
|
55
55
|
_VSCODE_EXT_RELOAD_REQUIRED = False # installed files are newer than the live host
|
|
56
56
|
_VSCODE_EXT_INSTALL_FAILED = False # automatic install could not complete safely
|
|
57
|
-
_VSCODE_EXT_VERSION = "0.14.
|
|
57
|
+
_VSCODE_EXT_VERSION = "0.14.87" # current bundled extension version
|
|
58
58
|
_VSCODE_CONFIGURED_PORTS: set[int] = set()
|
|
59
59
|
|
|
60
60
|
def _bundled_vscode_vsix_version(vsix_path: str) -> str | None:
|
|
@@ -633,6 +633,47 @@ def _ensure_vscode_extension(*, is_remote: bool | None = None) -> bool:
|
|
|
633
633
|
# ---------------------------------------------------------------------------
|
|
634
634
|
|
|
635
635
|
|
|
636
|
+
def _port_has_listener(port: int) -> bool:
|
|
637
|
+
"""Return True when something is listening on ``port`` on loopback."""
|
|
638
|
+
import socket
|
|
639
|
+
|
|
640
|
+
for family, addr in ((socket.AF_INET, "127.0.0.1"), (socket.AF_INET6, "::1")):
|
|
641
|
+
sock = socket.socket(family, socket.SOCK_STREAM)
|
|
642
|
+
try:
|
|
643
|
+
sock.settimeout(0.15)
|
|
644
|
+
if sock.connect_ex((addr, port)) == 0:
|
|
645
|
+
return True
|
|
646
|
+
except OSError:
|
|
647
|
+
continue
|
|
648
|
+
finally:
|
|
649
|
+
sock.close()
|
|
650
|
+
return False
|
|
651
|
+
|
|
652
|
+
|
|
653
|
+
def _stale_arrayview_port_keys(attrs: dict, keep_port: int) -> list[str]:
|
|
654
|
+
"""Return ArrayView port entries that no longer have a live server.
|
|
655
|
+
|
|
656
|
+
Every launch on a fresh port used to leave its entry behind for good. On a
|
|
657
|
+
tunnel those entries keep telling VS Code to forward ports nothing serves,
|
|
658
|
+
which competes for a limited per-tunnel forwarding budget. Only entries
|
|
659
|
+
ArrayView wrote are considered, and only when their port is dead, so a
|
|
660
|
+
second concurrent ArrayView server is never disturbed.
|
|
661
|
+
"""
|
|
662
|
+
stale: list[str] = []
|
|
663
|
+
for key, value in list(attrs.items()):
|
|
664
|
+
if not isinstance(value, dict) or value.get("label") != "ArrayView":
|
|
665
|
+
continue
|
|
666
|
+
if key == str(keep_port):
|
|
667
|
+
continue
|
|
668
|
+
try:
|
|
669
|
+
candidate = int(key)
|
|
670
|
+
except (TypeError, ValueError):
|
|
671
|
+
continue
|
|
672
|
+
if not _port_has_listener(candidate):
|
|
673
|
+
stale.append(key)
|
|
674
|
+
return stale
|
|
675
|
+
|
|
676
|
+
|
|
636
677
|
def _configure_vscode_port_preview(
|
|
637
678
|
port: int,
|
|
638
679
|
*,
|
|
@@ -686,8 +727,11 @@ def _configure_vscode_port_preview(
|
|
|
686
727
|
}
|
|
687
728
|
current = attrs.get(str(port))
|
|
688
729
|
updated = {**current, **desired} if isinstance(current, dict) else desired
|
|
689
|
-
|
|
730
|
+
stale = _stale_arrayview_port_keys(attrs, port)
|
|
731
|
+
if current == updated and not stale:
|
|
690
732
|
return
|
|
733
|
+
for key in stale:
|
|
734
|
+
attrs.pop(key, None)
|
|
691
735
|
attrs[str(port)] = updated
|
|
692
736
|
with open(path, "w") as f:
|
|
693
737
|
json.dump(settings, f, indent=2)
|
arrayview/arrayview-opener.vsix
CHANGED
|
Binary file
|
|
@@ -13,7 +13,7 @@ arrayview/_instance_registry.py,sha256=h7vyvCl0LTt9R8sDB1Vxe4a-KzfkLVuwrSw_ANpPT
|
|
|
13
13
|
arrayview/_io.py,sha256=jJ4FQEHggSHCz2zi3ZQK4NjoJpBt3OkklQbM4_Jp1f8,61303
|
|
14
14
|
arrayview/_launch_plan.py,sha256=UwmxmSZIFfutVZRhdlTZdrszCkxZMoSK99VvQHD-Mac,22192
|
|
15
15
|
arrayview/_launch_trace.py,sha256=sKNIEDSpI8OgEC0aSpcWJPu0zdHFcKpQr-sPfsfiTz8,3711
|
|
16
|
-
arrayview/_launcher.py,sha256=
|
|
16
|
+
arrayview/_launcher.py,sha256=ZBAvni9fgMW0Wj51RM1baDx3VH2jEaG2DP26A3OmFyU,206372
|
|
17
17
|
arrayview/_lifecycle.py,sha256=SzLBjoDq7pj9jnq12oERmM9HA_2N4Y-CxwCRsfK4Q1s,3840
|
|
18
18
|
arrayview/_overlays.py,sha256=TsMnXrP_BNSzCj4k8hbWNM-M5lcrro0xA_wusvAdLLw,4622
|
|
19
19
|
arrayview/_platform.py,sha256=RCCHtOaj3hZIlzENfeLbqO0MRZu-OfiVHGu1-jhpMeY,26461
|
|
@@ -21,11 +21,11 @@ arrayview/_render.py,sha256=wVvwxQtZ7ldWYZTzlg2CS-esnPHlpSXMW_z22eh-rU0,30296
|
|
|
21
21
|
arrayview/_routes_analysis.py,sha256=b2yiPm3qiapFPcBZWpltZrsTKNkFyHYV7o1O2ZrzVUo,32320
|
|
22
22
|
arrayview/_routes_drop.py,sha256=FC4e7STdCo3hYIA0C4Yy9Ka2UKFx7nLDU5dkujmc1Vo,12477
|
|
23
23
|
arrayview/_routes_export.py,sha256=Ha8mMO2E9TlRL5x25-ADV8_8xUiC-jRz9N1oWwgKOsg,3898
|
|
24
|
-
arrayview/_routes_loading.py,sha256=
|
|
24
|
+
arrayview/_routes_loading.py,sha256=yYzf7NJeE8fLviCbAcXMSiAtSlLVY-wHwfdUqDOBCNA,34055
|
|
25
25
|
arrayview/_routes_persistence.py,sha256=T03csHb7ppGT-8yMDf227XkqhnhjgSLYj0RW2wmg59g,17176
|
|
26
26
|
arrayview/_routes_preferences.py,sha256=78i0OhwVJ9JF2RNazWecctU1-PI_PhNAv7bBIVxuYNU,4483
|
|
27
27
|
arrayview/_routes_preload.py,sha256=KOsankNguxdIWmFW9iZcY9p2SvUN1mOKY7KkW1qMGcc,1729
|
|
28
|
-
arrayview/_routes_query.py,sha256=
|
|
28
|
+
arrayview/_routes_query.py,sha256=lzCoaz1fkRYC99QFBw0_6pLIlDEVNn99y_yH-q6DKzk,15825
|
|
29
29
|
arrayview/_routes_rendering.py,sha256=OiYvdYE2PnTXVo9fUdWN1JvZ-VvUTUgGA7LYGrmMDSo,21688
|
|
30
30
|
arrayview/_routes_segmentation.py,sha256=x2bBjQffZryeTMmOH38YdBWethw1o3KpA8V0chJcZHI,23599
|
|
31
31
|
arrayview/_routes_state.py,sha256=8TyTURrJKV0taVYK7c9L-Dcx_At-fhHI1l0-4OQMpU0,11615
|
|
@@ -33,22 +33,22 @@ arrayview/_routes_vectorfield.py,sha256=QDUTG46cMEm-FjFWeIs2cv3b494K_Y80c2Ff8DRK
|
|
|
33
33
|
arrayview/_routes_websocket.py,sha256=V5k_LhVw2pafItcuK5Q5kYYR4kmGfCRcaz7NRFG43S0,29043
|
|
34
34
|
arrayview/_segmentation.py,sha256=aENWHmefrKDScXhcZL1X3KgYXE784dpMkmFFo83qnrw,7377
|
|
35
35
|
arrayview/_server.py,sha256=NV6tRHo2OVR-PuSutGDAkYYSafD2exZfggUoUcXzti0,11797
|
|
36
|
-
arrayview/_session.py,sha256=
|
|
36
|
+
arrayview/_session.py,sha256=eNE4GQBhvKKCAB_DkfIpjVDMBRo4CD9X3pJbaZmNVH8,22641
|
|
37
37
|
arrayview/_session_spec.py,sha256=mKDfMRsPYQdEmN9hLXmDU_9N7etiDyBXr8mz-fB8QBo,6825
|
|
38
38
|
arrayview/_shell.html,sha256=vNa2Kiwx_eoB5H329jolYafLhwJDCH9DsJafBqvVMWU,13194
|
|
39
39
|
arrayview/_synthetic_mri.py,sha256=CNL-2WC835i6WCqkvmWBCO6WQ5w7HE5trNb8OyEfe64,7365
|
|
40
40
|
arrayview/_torch.py,sha256=13sqIMCUu_-b9SQ9KfDCExDz2UMStL87EDVjnbJxAEo,7536
|
|
41
41
|
arrayview/_vectorfield.py,sha256=eDqMCMEGjO8Jdt-6Auh01cz3WD9dbF7xYUWD9xHAf1E,8115
|
|
42
|
-
arrayview/_viewer.html,sha256=
|
|
42
|
+
arrayview/_viewer.html,sha256=jwqjyk4Vl5aUFAVdGmM-CRETldBcqpVIZmUSO9LZ0Jc,1887238
|
|
43
43
|
arrayview/_vscode.py,sha256=EKnGN2zrjlybc4FQOmYA8BvYdtkcJbLHDEdgtvO7ul4,837
|
|
44
44
|
arrayview/_vscode_browser.py,sha256=kTdux_l-xax5qYEX2zU5xGscceBrnlZUaX1i28bZ0jI,18950
|
|
45
|
-
arrayview/_vscode_extension.py,sha256=
|
|
45
|
+
arrayview/_vscode_extension.py,sha256=n4dcV5x2gxCx3o0ghd2tmtJYLVwrhYDp9GEQKBQFS_M,30137
|
|
46
46
|
arrayview/_vscode_signal.py,sha256=8pGVjuzUzIu9bNSZkczF8guzblS1oHyefFplAebrjBU,45559
|
|
47
|
-
arrayview/arrayview-opener.vsix,sha256=
|
|
47
|
+
arrayview/arrayview-opener.vsix,sha256=zYr0bpA2WN_oL8sNq0vCF4SqsRZlNiDncl-K7A8o3PM,38458
|
|
48
48
|
arrayview/gsap.min.js,sha256=VGihm4idI0E1uqrWezWsiScB9F_jMosn7qs6pPSkeac,72304
|
|
49
49
|
arrayview/todo.md,sha256=4rzoaIY4nJJACDHPJKeqP8guasCMxeRQ1cyNLxUYink,999
|
|
50
|
-
arrayview-0.
|
|
51
|
-
arrayview-0.
|
|
52
|
-
arrayview-0.
|
|
53
|
-
arrayview-0.
|
|
54
|
-
arrayview-0.
|
|
50
|
+
arrayview-0.36.0.dist-info/METADATA,sha256=RFS3W_onLeEjsc_EGYKynB7-kqPYdGnEgx3LziJ-bnU,2345
|
|
51
|
+
arrayview-0.36.0.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
52
|
+
arrayview-0.36.0.dist-info/entry_points.txt,sha256=FQSz3M11B-zaVLDyXofKUDvMhHASz7OjmoLgI4nn7ko,105
|
|
53
|
+
arrayview-0.36.0.dist-info/licenses/LICENSE,sha256=34OivjM9faB2QaPjZpMRTIiSx31V3U9cEyQ6F2k-bH0,1062
|
|
54
|
+
arrayview-0.36.0.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|