arrayview 0.47.3__py3-none-any.whl → 0.47.4__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/_io.py +68 -4
- arrayview/_launcher.py +12 -11
- arrayview/_routes_loading.py +11 -11
- arrayview/_source_safety.py +2 -0
- arrayview/_vscode_extension.py +1 -1
- arrayview/arrayview-opener.vsix +0 -0
- {arrayview-0.47.3.dist-info → arrayview-0.47.4.dist-info}/METADATA +1 -1
- {arrayview-0.47.3.dist-info → arrayview-0.47.4.dist-info}/RECORD +11 -11
- {arrayview-0.47.3.dist-info → arrayview-0.47.4.dist-info}/WHEEL +0 -0
- {arrayview-0.47.3.dist-info → arrayview-0.47.4.dist-info}/entry_points.txt +0 -0
- {arrayview-0.47.3.dist-info → arrayview-0.47.4.dist-info}/licenses/LICENSE +0 -0
arrayview/_io.py
CHANGED
|
@@ -667,7 +667,7 @@ class _FileSeries:
|
|
|
667
667
|
"""Lazy 4D/5D view over a directory of same-shape array files.
|
|
668
668
|
|
|
669
669
|
Like ``_NiftiSeries`` but works with any supported file format
|
|
670
|
-
(.npy, .npz, .zarr, .pt/.pth, .h5/.hdf5, .tif/.tiff, .mat).
|
|
670
|
+
(.npy, .npz, .zarr, .pt/.pth, .h5/.hdf5, .tif/.tiff, .mat, .gipl).
|
|
671
671
|
Uses ``load_data`` for each volume — no nibabel reorientation.
|
|
672
672
|
"""
|
|
673
673
|
|
|
@@ -940,6 +940,8 @@ def _get_ext(filepath):
|
|
|
940
940
|
return ".nii.gz"
|
|
941
941
|
if lower.endswith(".zarr.zip"):
|
|
942
942
|
return ".zarr.zip"
|
|
943
|
+
if lower.endswith(".gipl.gz"):
|
|
944
|
+
return ".gipl.gz"
|
|
943
945
|
return os.path.splitext(lower)[1]
|
|
944
946
|
|
|
945
947
|
|
|
@@ -950,7 +952,7 @@ def _is_supported_collection_path(filepath):
|
|
|
950
952
|
def _strip_array_ext(filepath):
|
|
951
953
|
base = os.path.basename(filepath)
|
|
952
954
|
lower = base.lower()
|
|
953
|
-
for suffix in (".nii.gz", ".zarr.zip"):
|
|
955
|
+
for suffix in (".nii.gz", ".zarr.zip", ".gipl.gz"):
|
|
954
956
|
if lower.endswith(suffix):
|
|
955
957
|
return base[: -len(suffix)]
|
|
956
958
|
return os.path.splitext(base)[0]
|
|
@@ -1738,6 +1740,8 @@ def load_data(filepath, key=None, *, progress=None):
|
|
|
1738
1740
|
import tifffile
|
|
1739
1741
|
|
|
1740
1742
|
return tifffile.imread(filepath)
|
|
1743
|
+
elif filepath.lower().endswith((".gipl", ".gipl.gz")):
|
|
1744
|
+
return _load_gipl(filepath)
|
|
1741
1745
|
elif filepath.endswith(".mat"):
|
|
1742
1746
|
try:
|
|
1743
1747
|
import scipy.io
|
|
@@ -1783,10 +1787,68 @@ def load_data(filepath, key=None, *, progress=None):
|
|
|
1783
1787
|
return data
|
|
1784
1788
|
raise ValueError(
|
|
1785
1789
|
"Unsupported format. Supported: .npy, .npz, .nii/.nii.gz, .zarr, "
|
|
1786
|
-
".pt/.pth, .h5/.hdf5, .tif/.tiff, .mat"
|
|
1790
|
+
".pt/.pth, .h5/.hdf5, .tif/.tiff, .mat, .gipl/.gipl.gz"
|
|
1787
1791
|
)
|
|
1788
1792
|
|
|
1789
1793
|
|
|
1794
|
+
# GIPL (Guys Image Processing Lab) image types -> numpy dtypes. Data is
|
|
1795
|
+
# big-endian; complex types store interleaved real/imaginary components.
|
|
1796
|
+
_GIPL_DTYPES = {
|
|
1797
|
+
1: ">u1", # binary, one value per byte
|
|
1798
|
+
7: ">i1",
|
|
1799
|
+
8: ">u1",
|
|
1800
|
+
15: ">i2",
|
|
1801
|
+
16: ">u2",
|
|
1802
|
+
31: ">u4",
|
|
1803
|
+
32: ">i4",
|
|
1804
|
+
64: ">f4",
|
|
1805
|
+
65: ">f8",
|
|
1806
|
+
144: ">i2", # complex short
|
|
1807
|
+
160: ">i4", # complex int
|
|
1808
|
+
192: ">f4", # complex float
|
|
1809
|
+
193: ">f8", # complex double
|
|
1810
|
+
}
|
|
1811
|
+
_GIPL_COMPLEX = frozenset([144, 160, 192, 193])
|
|
1812
|
+
_GIPL_MAGIC = (4026526128, 719555000)
|
|
1813
|
+
_GIPL_HEADER_SIZE = 256
|
|
1814
|
+
|
|
1815
|
+
|
|
1816
|
+
def _load_gipl(filepath):
|
|
1817
|
+
"""Read a .gipl/.gipl.gz file into an array indexed (x, y, z, t).
|
|
1818
|
+
|
|
1819
|
+
Trailing singleton dimensions are dropped, matching how a NIfTI volume
|
|
1820
|
+
of the same data is shown.
|
|
1821
|
+
"""
|
|
1822
|
+
import gzip
|
|
1823
|
+
|
|
1824
|
+
opener = gzip.open if filepath.lower().endswith(".gz") else open
|
|
1825
|
+
with opener(filepath, "rb") as f:
|
|
1826
|
+
raw = f.read()
|
|
1827
|
+
if len(raw) < _GIPL_HEADER_SIZE:
|
|
1828
|
+
raise ValueError(f"{filepath!r} is too short to be a GIPL file.")
|
|
1829
|
+
header = raw[:_GIPL_HEADER_SIZE]
|
|
1830
|
+
magic = int(np.frombuffer(header, ">u4", count=1, offset=252)[0])
|
|
1831
|
+
if magic not in _GIPL_MAGIC:
|
|
1832
|
+
raise ValueError(f"{filepath!r} is not a GIPL file (bad magic number).")
|
|
1833
|
+
dims = [int(d) for d in np.frombuffer(header, ">u2", count=4, offset=0)]
|
|
1834
|
+
image_type = int(np.frombuffer(header, ">u2", count=1, offset=8)[0])
|
|
1835
|
+
if image_type not in _GIPL_DTYPES:
|
|
1836
|
+
raise ValueError(f"{filepath!r} has unsupported GIPL image type {image_type}.")
|
|
1837
|
+
dims = [max(d, 1) for d in dims]
|
|
1838
|
+
is_complex = image_type in _GIPL_COMPLEX
|
|
1839
|
+
count = int(np.prod(dims)) * (2 if is_complex else 1)
|
|
1840
|
+
data = np.frombuffer(raw, _GIPL_DTYPES[image_type], count=count, offset=_GIPL_HEADER_SIZE)
|
|
1841
|
+
data = data.astype(data.dtype.newbyteorder("="))
|
|
1842
|
+
if is_complex:
|
|
1843
|
+
data = data.astype(np.float64 if data.itemsize == 8 else np.float32)
|
|
1844
|
+
data = data[0::2] + 1j * data[1::2]
|
|
1845
|
+
# x varies fastest on disk.
|
|
1846
|
+
arr = data.reshape(dims[::-1]).transpose(3, 2, 1, 0)
|
|
1847
|
+
while arr.ndim > 2 and arr.shape[-1] == 1:
|
|
1848
|
+
arr = arr[..., 0]
|
|
1849
|
+
return np.ascontiguousarray(arr)
|
|
1850
|
+
|
|
1851
|
+
|
|
1790
1852
|
def _tensor_to_numpy(obj, source="object"):
|
|
1791
1853
|
"""Convert a tensor-like object (PyTorch, etc.) to a numpy array."""
|
|
1792
1854
|
if isinstance(obj, np.ndarray):
|
|
@@ -1823,13 +1885,15 @@ _SUPPORTED_EXTS = frozenset(
|
|
|
1823
1885
|
".tif",
|
|
1824
1886
|
".tiff",
|
|
1825
1887
|
".mat",
|
|
1888
|
+
".gipl",
|
|
1889
|
+
".gipl.gz",
|
|
1826
1890
|
".dcm",
|
|
1827
1891
|
]
|
|
1828
1892
|
)
|
|
1829
1893
|
|
|
1830
1894
|
# Formats that load the entire array into RAM (no mmap/lazy access).
|
|
1831
1895
|
# RAM guard only applies to these.
|
|
1832
|
-
FULL_LOAD_EXTS = frozenset([".pt", ".pth", ".tif", ".tiff", ".mat"])
|
|
1896
|
+
FULL_LOAD_EXTS = frozenset([".pt", ".pth", ".tif", ".tiff", ".mat", ".gipl", ".gipl.gz"])
|
|
1833
1897
|
|
|
1834
1898
|
|
|
1835
1899
|
def _peek_file_shape(fpath: str, ext: str):
|
arrayview/_launcher.py
CHANGED
|
@@ -6211,17 +6211,18 @@ def arrayview():
|
|
|
6211
6211
|
pattern for _name, pattern in _normalize_dir_overlay_specs(args.overlay or [])
|
|
6212
6212
|
)
|
|
6213
6213
|
collection_inputs.extend(args.overlay_dir or [])
|
|
6214
|
-
|
|
6215
|
-
pattern
|
|
6216
|
-
|
|
6217
|
-
|
|
6218
|
-
|
|
6219
|
-
|
|
6220
|
-
|
|
6221
|
-
|
|
6222
|
-
|
|
6223
|
-
|
|
6224
|
-
|
|
6214
|
+
if os.environ.get("ARRAYVIEW_SKIP_SOURCE_STAGING", "1") == "0":
|
|
6215
|
+
for pattern in collection_inputs:
|
|
6216
|
+
pattern = lexical_abspath(pattern)
|
|
6217
|
+
probe_prefix = scan_root_before_magic(pattern)
|
|
6218
|
+
mount = direct_network_mount(probe_prefix)
|
|
6219
|
+
nested_mount = network_mount_below(probe_prefix)
|
|
6220
|
+
if mount is not None or nested_mount is not None:
|
|
6221
|
+
_print_failure(
|
|
6222
|
+
"network directory collections are not accessed directly. "
|
|
6223
|
+
"Copy the collection to local storage before using --match."
|
|
6224
|
+
)
|
|
6225
|
+
sys.exit(1)
|
|
6225
6226
|
if len(dir_patterns) == 1 and os.path.isdir(dir_patterns[0]):
|
|
6226
6227
|
dir_patterns = [os.path.join(dir_patterns[0], "**", "*")]
|
|
6227
6228
|
dir_overlay_specs = [
|
arrayview/_routes_loading.py
CHANGED
|
@@ -167,17 +167,17 @@ def register_loading_routes(app, *, notify_shells, setup_rgb) -> None:
|
|
|
167
167
|
f"{nested_sibling_mount.mountpoint!r}; copy the series locally first."
|
|
168
168
|
)
|
|
169
169
|
}
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
170
|
+
for pattern in dir_patterns or []:
|
|
171
|
+
pattern_path = lexical_abspath(str(pattern))
|
|
172
|
+
scan_root = scan_root_before_magic(pattern_path)
|
|
173
|
+
unsafe_mount = direct_network_mount(scan_root) or network_mount_below(scan_root)
|
|
174
|
+
if unsafe_mount is not None:
|
|
175
|
+
return {
|
|
176
|
+
"error": (
|
|
177
|
+
f"Directory scan would enter network mount "
|
|
178
|
+
f"{unsafe_mount.mountpoint!r}; copy the collection locally first."
|
|
179
|
+
)
|
|
180
|
+
}
|
|
181
181
|
if requested_sid in CANCELLED_PENDING_SESSIONS:
|
|
182
182
|
CANCELLED_PENDING_SESSIONS.discard(requested_sid)
|
|
183
183
|
raise HTTPException(status_code=409, detail="load request was cancelled")
|
arrayview/_source_safety.py
CHANGED
arrayview/_vscode_extension.py
CHANGED
|
@@ -58,7 +58,7 @@ _VSCODE_EXT_FRESH_INSTALL = False # True if we just installed it this session
|
|
|
58
58
|
_VSCODE_EXT_RELOAD_REQUIRED = False # installed files are newer than the live host
|
|
59
59
|
_VSCODE_EXT_INSTALL_FAILED = False # automatic install could not complete safely
|
|
60
60
|
_VSCODE_EXT_NO_LIVE_WINDOW = False # no live host claims this terminal's window id
|
|
61
|
-
_VSCODE_EXT_VERSION = "0.15.
|
|
61
|
+
_VSCODE_EXT_VERSION = "0.15.64" # current bundled extension version
|
|
62
62
|
_VSCODE_CONFIGURED_PORTS: set[int] = set()
|
|
63
63
|
# Version-skew notices already printed, so a long-lived process (Jupyter, a
|
|
64
64
|
# script opening several arrays) states the mismatch once instead of per call.
|
arrayview/arrayview-opener.vsix
CHANGED
|
Binary file
|
|
@@ -12,10 +12,10 @@ arrayview/_extra_ports.py,sha256=MZcx04NI9Eg4coydb-yPIHp7uJbE6UscyYGnw8fxid0,111
|
|
|
12
12
|
arrayview/_icon.png,sha256=a8RTAbvweLhh3hzD5eGg76Peq-KSDcS6YrCphRb_HEs,2748
|
|
13
13
|
arrayview/_imaging.py,sha256=MQX1uy4m1lofOeoLDhCp6cHO5p_V5fXm4qlSu9Ykn-c,534
|
|
14
14
|
arrayview/_instance_registry.py,sha256=h7vyvCl0LTt9R8sDB1Vxe4a-KzfkLVuwrSw_ANpPTD8,8833
|
|
15
|
-
arrayview/_io.py,sha256=
|
|
15
|
+
arrayview/_io.py,sha256=u1wrxfEA3kRT9n6tV-7ptcQxr1mOylZaREYq3Ex6nvM,77652
|
|
16
16
|
arrayview/_launch_plan.py,sha256=KGgIPGsflXArECB2txnIAewjuPvF4fZTbO63alC8x28,23570
|
|
17
17
|
arrayview/_launch_trace.py,sha256=4yjJdkFyEvSrPN14QVFJ3u6on2q0TH2ySSdgUp9SjKI,5668
|
|
18
|
-
arrayview/_launcher.py,sha256=
|
|
18
|
+
arrayview/_launcher.py,sha256=Eu1XFLhuXiO45StFWZoSPPjFkBLqcEeqGB8Utx7kotQ,243224
|
|
19
19
|
arrayview/_lifecycle.py,sha256=bqG0oKr-e-5S1ssCTlGmF-yBE47ilrpO1S_Owfjs9Z8,5365
|
|
20
20
|
arrayview/_overlays.py,sha256=CksypG9rWfCz_3RRGIeyaKeXse17AFxvkEjmYyXnIIE,5399
|
|
21
21
|
arrayview/_platform.py,sha256=qSWjRcx9rLIdLvKrRArSueFnbyn5GPKfTEMOc5mCIUs,29970
|
|
@@ -23,7 +23,7 @@ arrayview/_render.py,sha256=sSNPWreJumIyFKvZtAS5v2gxbNHRVyAdc7JGj34caPw,34121
|
|
|
23
23
|
arrayview/_routes_analysis.py,sha256=Xz9Ysr04u07pzSRB4Fzmcl6XwVxyaG6xCWxGwYZi_80,33085
|
|
24
24
|
arrayview/_routes_drop.py,sha256=FC4e7STdCo3hYIA0C4Yy9Ka2UKFx7nLDU5dkujmc1Vo,12477
|
|
25
25
|
arrayview/_routes_export.py,sha256=Ha8mMO2E9TlRL5x25-ADV8_8xUiC-jRz9N1oWwgKOsg,3898
|
|
26
|
-
arrayview/_routes_loading.py,sha256=
|
|
26
|
+
arrayview/_routes_loading.py,sha256=r88PRn1ogSRe1Ec0odhCN3jd5FwIDH0y7acPdUoY9v0,42404
|
|
27
27
|
arrayview/_routes_persistence.py,sha256=T03csHb7ppGT-8yMDf227XkqhnhjgSLYj0RW2wmg59g,17176
|
|
28
28
|
arrayview/_routes_preferences.py,sha256=xoMHbPKliYspgjaclhx2r8HbP9mFo9Td-nTF76eWVMg,4680
|
|
29
29
|
arrayview/_routes_preload.py,sha256=KOsankNguxdIWmFW9iZcY9p2SvUN1mOKY7KkW1qMGcc,1729
|
|
@@ -38,7 +38,7 @@ arrayview/_server.py,sha256=A8O8J6N4WTDcujFHjTWjlJYWIzkJe8y9XmKpj9XozE0,22918
|
|
|
38
38
|
arrayview/_session.py,sha256=-Jems6lGOVU3uLs4Uq1ggIfY-qTrAXNzpUk6nMbuTBA,35616
|
|
39
39
|
arrayview/_session_spec.py,sha256=mKDfMRsPYQdEmN9hLXmDU_9N7etiDyBXr8mz-fB8QBo,6825
|
|
40
40
|
arrayview/_shell.html,sha256=vNa2Kiwx_eoB5H329jolYafLhwJDCH9DsJafBqvVMWU,13194
|
|
41
|
-
arrayview/_source_safety.py,sha256=
|
|
41
|
+
arrayview/_source_safety.py,sha256=cI7JAL7DWYuxuB_LnYExvJZaICX2R2qJEJWD1M0z_gg,27664
|
|
42
42
|
arrayview/_synthetic_mri.py,sha256=CNL-2WC835i6WCqkvmWBCO6WQ5w7HE5trNb8OyEfe64,7365
|
|
43
43
|
arrayview/_torch.py,sha256=13sqIMCUu_-b9SQ9KfDCExDz2UMStL87EDVjnbJxAEo,7536
|
|
44
44
|
arrayview/_tutorial.py,sha256=2zZHJGJDa4n30GE1-9ADjKFAifGBH9vvHXP4uDt7BaA,19547
|
|
@@ -46,14 +46,14 @@ arrayview/_vectorfield.py,sha256=eDqMCMEGjO8Jdt-6Auh01cz3WD9dbF7xYUWD9xHAf1E,811
|
|
|
46
46
|
arrayview/_viewer.html,sha256=aiHPSbCCtj90EnHV0nJ7kh8YkxAaUmzdDYJGW5KC0Zg,2372368
|
|
47
47
|
arrayview/_vscode.py,sha256=EKnGN2zrjlybc4FQOmYA8BvYdtkcJbLHDEdgtvO7ul4,837
|
|
48
48
|
arrayview/_vscode_browser.py,sha256=VCH9JpAAjFuhO0wQe8tIGjAL5837AXg_bpmBFtWOQqc,20573
|
|
49
|
-
arrayview/_vscode_extension.py,sha256=
|
|
49
|
+
arrayview/_vscode_extension.py,sha256=tF62xp_zVDMexlPtAZ7wKvKCKakdygmf3IGIcICoKeE,53156
|
|
50
50
|
arrayview/_vscode_signal.py,sha256=N3PCHG6-3tCEc_tHLjg2dhSEQ2EnF_psE2IJRBpAuac,54938
|
|
51
51
|
arrayview/_watch.py,sha256=PxxS_5hcj_S6xQf9Ep4p1HLRkrI5iDMh1aRa4olV7ew,1873
|
|
52
|
-
arrayview/arrayview-opener.vsix,sha256=
|
|
52
|
+
arrayview/arrayview-opener.vsix,sha256=BpRLXxm4j9gc34xusHzE80g01m6CvIK_fzf3ApgS5xE,61442
|
|
53
53
|
arrayview/gsap.min.js,sha256=VGihm4idI0E1uqrWezWsiScB9F_jMosn7qs6pPSkeac,72304
|
|
54
54
|
arrayview/todo.md,sha256=KhnRzpn6_jezR0nDDB61-zhox-rbOmEGW-A7Z0_7FnU,622
|
|
55
|
-
arrayview-0.47.
|
|
56
|
-
arrayview-0.47.
|
|
57
|
-
arrayview-0.47.
|
|
58
|
-
arrayview-0.47.
|
|
59
|
-
arrayview-0.47.
|
|
55
|
+
arrayview-0.47.4.dist-info/METADATA,sha256=V3wlriyNB8GhY_UZwcin_BktoAU6pkum8vDVg6FYVCY,2288
|
|
56
|
+
arrayview-0.47.4.dist-info/WHEEL,sha256=W3fkpkm7-wf9vBI5Z-7s0eWkeM-spu78I8Neb98DeEg,87
|
|
57
|
+
arrayview-0.47.4.dist-info/entry_points.txt,sha256=-0s08axutXkTbINiKs0Q7iv-33aWuTaamUg2q2-NyQ4,60
|
|
58
|
+
arrayview-0.47.4.dist-info/licenses/LICENSE,sha256=34OivjM9faB2QaPjZpMRTIiSx31V3U9cEyQ6F2k-bH0,1062
|
|
59
|
+
arrayview-0.47.4.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|