Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ced263441 | ||
|
|
e9ea4c5248 | ||
|
|
ae7868d410 |
@@ -38,11 +38,6 @@ If you want to cite this work, you can cite it from Zenodo:
|
||||
|
||||
[](https://zenodo.org/badge/latestdoi/786623459)
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Only one cutter supported in EEVEE render
|
||||
- Shader fail to work when convert to mesh.
|
||||
- Section surface cannot be generated when convert to mesh (will be supported soon)
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
@@ -49,15 +49,8 @@ Welcome to our [discord server](https://discord.gg/pYkNyq2TjE), if you have any
|
||||
|
||||

|
||||
|
||||
👍 EEVEE NEXT is absolutely AWESOME! Bioxel Nodes is fully support EEVEE NEXT now! However, there are some limitations:
|
||||
👍 EEVEE NEXT is absolutely AWESOME! Bioxel Nodes is fully support EEVEE NEXT now!
|
||||
|
||||
1. Only one cutter supported.
|
||||
2. EEVEE result is not that great as Cycles does.
|
||||
|
||||
## Known Limitations
|
||||
|
||||
- Only works with Cycles CPU , Cycles GPU (OptiX), EEVEE
|
||||
- Section surface cannot be generated when convert to mesh (will be supported soon)
|
||||
|
||||
## Roadmap
|
||||
|
||||
|
||||
@@ -49,15 +49,7 @@ Bioxel Nodes 是一款用于科学体数据可视化的 Blender 插件。它利
|
||||
|
||||

|
||||
|
||||
EEVEE NEXT 太棒了!Bioxel Nodes 现在全面支持 EEVEE NEXT!但仍有以下限制:
|
||||
|
||||
1. 仅支持一个切割器
|
||||
2. EEVEE 渲染效果不如 Cycles
|
||||
|
||||
## 已知限制
|
||||
|
||||
- 仅支持 Cycles CPU、Cycles GPU (OptiX)、EEVEE
|
||||
- 转换为网格时无法生成剖面(即将支持)
|
||||
EEVEE NEXT 太棒了!Bioxel Nodes 现在全面支持 EEVEE NEXT!
|
||||
|
||||
## 路线图
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[project]
|
||||
name = "bioxelnodes"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
description = ""
|
||||
authors = [{ name = "MaNan", email = "icrdr2010@outlook.com" }]
|
||||
requires-python = ">=3.11.0,<3.12.dev0"
|
||||
|
||||
@@ -9,6 +9,8 @@ from . import menus
|
||||
|
||||
auto_load.init()
|
||||
|
||||
CLI_COMMAND_NAME = "bioxelnodes_import_worker"
|
||||
|
||||
|
||||
def register():
|
||||
pcoll = previews.new()
|
||||
@@ -41,9 +43,11 @@ def register():
|
||||
|
||||
auto_load.register()
|
||||
menus.add()
|
||||
register_cli_commands()
|
||||
|
||||
|
||||
def unregister():
|
||||
unregister_cli_commands()
|
||||
menus.remove()
|
||||
auto_load.unregister()
|
||||
|
||||
@@ -56,3 +60,21 @@ def unregister():
|
||||
for pcoll in PREVIEW_COLLECTIONS.values():
|
||||
previews.remove(pcoll)
|
||||
PREVIEW_COLLECTIONS.clear()
|
||||
|
||||
|
||||
def import_worker_cli(args):
|
||||
from .operators import io_worker
|
||||
|
||||
return io_worker.main(args)
|
||||
|
||||
|
||||
def register_cli_commands():
|
||||
unregister_cli_commands()
|
||||
bpy.utils.register_cli_command(CLI_COMMAND_NAME, import_worker_cli)
|
||||
|
||||
|
||||
def unregister_cli_commands():
|
||||
try:
|
||||
bpy.utils.unregister_cli_command(CLI_COMMAND_NAME)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
schema_version = "1.0.0"
|
||||
|
||||
id = "bioxelnodes"
|
||||
version = "2.0.1"
|
||||
version = "2.0.2"
|
||||
name = "Bioxel Nodes"
|
||||
tagline = "For scientific volumetric data visualization in Blender"
|
||||
maintainer = "Nan <icrdr2010@outlook.com>"
|
||||
|
||||
@@ -13,7 +13,7 @@ import SimpleITK as sitk
|
||||
from ..props import BIOXEL_Series
|
||||
from ..utils import get_layer_obj, wrapped_label
|
||||
|
||||
from ..bioxel.parse import DICOM_EXTS, SUPPORT_EXTS, get_ext
|
||||
from ..bioxel.parse import DICOM_EXTS, SUPPORT_EXTS, get_ext, parse_volumetric_data
|
||||
|
||||
from ..utils import get_cache_dir, progress_update, progress_bar
|
||||
from ..layer import get_layer_caches, set_layer_caches
|
||||
@@ -61,6 +61,14 @@ def remove_progress_bar_safe():
|
||||
pass
|
||||
|
||||
|
||||
def get_addon_module_name():
|
||||
package_name = __package__ or "bioxelnodes.operators"
|
||||
suffix = ".operators"
|
||||
if package_name.endswith(suffix):
|
||||
return package_name[: -len(suffix)]
|
||||
return package_name
|
||||
|
||||
|
||||
def start_worker_process(owner, command: str, payload: dict):
|
||||
job_dir = Path(tempfile.mkdtemp(prefix="bioxel_import_", dir=str(get_cache_dir())))
|
||||
config_path = job_dir / "config.json"
|
||||
@@ -69,24 +77,29 @@ def start_worker_process(owner, command: str, payload: dict):
|
||||
cancel_path = job_dir / "cancel"
|
||||
log_path = job_dir / "worker.log"
|
||||
|
||||
addon_name = get_addon_module_name()
|
||||
config = {
|
||||
**payload,
|
||||
"command": command,
|
||||
"addon_name": addon_name,
|
||||
"progress_path": str(progress_path),
|
||||
"result_path": str(result_path),
|
||||
"cancel_path": str(cancel_path),
|
||||
}
|
||||
write_worker_json(config_path, config)
|
||||
write_worker_json(progress_path, {"factor": 0.0, "text": "Starting..."})
|
||||
write_worker_json(
|
||||
progress_path,
|
||||
{"factor": 0.0, "text": "Starting background Blender..."},
|
||||
)
|
||||
|
||||
worker_path = Path(__file__).with_name("io_worker.py")
|
||||
print(f"Starting Bioxel worker with addon module: {addon_name}")
|
||||
cmd = [
|
||||
bpy.app.binary_path,
|
||||
"--background",
|
||||
"--factory-startup",
|
||||
"--python",
|
||||
str(worker_path),
|
||||
"--",
|
||||
"--addons",
|
||||
addon_name,
|
||||
"--command",
|
||||
"bioxelnodes_import_worker",
|
||||
str(config_path),
|
||||
]
|
||||
|
||||
@@ -188,7 +201,6 @@ class ImportDataBase:
|
||||
context.window_manager.fileselect_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
|
||||
class ImportData(bpy.types.Operator, ImportDataBase):
|
||||
bl_idname = "bioxel.import_data"
|
||||
bl_label = "Import Data"
|
||||
@@ -291,64 +303,26 @@ class ParseVolumetricData(bpy.types.Operator):
|
||||
|
||||
def execute(self, context):
|
||||
print("Collecting Meta Data...")
|
||||
self.is_cancelled = False
|
||||
self.has_error = None
|
||||
self.meta = None
|
||||
self.label_count = 0
|
||||
self.dtype = None
|
||||
progress_update(context, 0.0, "Collecting Meta Data...")
|
||||
|
||||
start_worker_process(
|
||||
self,
|
||||
"read_meta",
|
||||
{
|
||||
"filepath": self.filepath,
|
||||
"series_id": self.series_id,
|
||||
},
|
||||
def progress_callback(factor, text):
|
||||
progress_update(context, factor, text)
|
||||
|
||||
try:
|
||||
series_id = self.series_id if self.series_id != "empty" else ""
|
||||
data, meta = parse_volumetric_data(
|
||||
data_file=self.filepath,
|
||||
series_id=series_id,
|
||||
progress_callback=progress_callback,
|
||||
)
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
self._timer = context.window_manager.event_timer_add(
|
||||
time_step=0.1, window=context.window
|
||||
)
|
||||
bpy.types.STATUSBAR_HT_header.append(progress_bar)
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {"RUNNING_MODAL"}
|
||||
|
||||
def modal(self, context, event):
|
||||
if event.type == "ESC":
|
||||
cancel_worker_process(self, context)
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
if event.type != "TIMER":
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
bpy.context.workspace.status_text_set_internal(None)
|
||||
update_worker_progress(self, context)
|
||||
|
||||
if self.process.poll() is None:
|
||||
return {"PASS_THROUGH"}
|
||||
|
||||
context.window_manager.event_timer_remove(self._timer)
|
||||
remove_progress_bar_safe()
|
||||
self.meta = meta
|
||||
self.label_count = int(np.max(data))
|
||||
self.dtype = data.dtype
|
||||
progress_update(context, 1.0)
|
||||
|
||||
result = read_worker_json(self.result_path)
|
||||
if self.is_cancelled or (result and result.get("cancelled")):
|
||||
self.report({"WARNING"}, "Canncelled by user.")
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not result:
|
||||
self.report({"ERROR"}, f"Import worker failed. See log: {self.log_path}")
|
||||
return {"CANCELLED"}
|
||||
|
||||
if not result.get("ok"):
|
||||
print(result.get("traceback", ""))
|
||||
self.report({"ERROR"}, result.get("error", "Import worker failed."))
|
||||
return {"CANCELLED"}
|
||||
|
||||
self.meta = result["meta"]
|
||||
self.label_count = int(result["label_count"])
|
||||
self.dtype = np.dtype(result["dtype"])
|
||||
|
||||
for key, value in self.meta.items():
|
||||
print(f"{key}: {value}")
|
||||
|
||||
|
||||
@@ -1,24 +1,7 @@
|
||||
import json
|
||||
import sys
|
||||
import traceback
|
||||
from pathlib import Path
|
||||
|
||||
import numpy as np
|
||||
import transforms3d
|
||||
|
||||
if __package__:
|
||||
from ..bioxel.layer import Layer
|
||||
from ..bioxel.parse import parse_volumetric_data
|
||||
from ..layer import save_layers_to_cache
|
||||
else:
|
||||
PACKAGE_PARENT = Path(__file__).resolve().parents[2]
|
||||
if str(PACKAGE_PARENT) not in sys.path:
|
||||
sys.path.insert(0, str(PACKAGE_PARENT))
|
||||
|
||||
from bioxelnodes.bioxel.layer import Layer
|
||||
from bioxelnodes.bioxel.parse import parse_volumetric_data
|
||||
from bioxelnodes.layer import save_layers_to_cache
|
||||
|
||||
|
||||
def get_layer_shape(bioxel_size: float, orig_shape: tuple, orig_spacing: tuple):
|
||||
shape = (
|
||||
@@ -72,6 +55,10 @@ def progress_callback_factory(progress_path: Path, cancel_path: Path, layer_name
|
||||
|
||||
|
||||
def read_meta(config, progress_path: Path, cancel_path: Path):
|
||||
import numpy as np
|
||||
|
||||
from ..bioxel.parse import parse_volumetric_data
|
||||
|
||||
progress_callback = make_progress_writer(progress_path, cancel_path)
|
||||
series_id = config["series_id"] if config["series_id"] != "empty" else ""
|
||||
data, meta = parse_volumetric_data(
|
||||
@@ -94,6 +81,13 @@ def read_meta(config, progress_path: Path, cancel_path: Path):
|
||||
|
||||
|
||||
def build_layers(config, progress_path: Path, cancel_path: Path):
|
||||
import numpy as np
|
||||
import transforms3d
|
||||
|
||||
from ..bioxel.layer import Layer
|
||||
from ..bioxel.parse import parse_volumetric_data
|
||||
from ..layer import save_layers_to_cache
|
||||
|
||||
write_json(progress_path, {"factor": 0.0, "text": "Parsing Volumetirc Data..."})
|
||||
progress_callback = make_progress_writer(progress_path, cancel_path, scale=0.2)
|
||||
data, meta = parse_volumetric_data(
|
||||
@@ -229,14 +223,19 @@ def build_layers(config, progress_path: Path, cancel_path: Path):
|
||||
return {"cache_infos": cache_infos, "added_ids": [item["id"] for item in cache_infos]}
|
||||
|
||||
|
||||
def main():
|
||||
config_path = Path(sys.argv[-1])
|
||||
def main(args):
|
||||
if not args:
|
||||
print("Usage: blender --command bioxelnodes_import_worker <config_path>")
|
||||
return 2
|
||||
|
||||
config_path = Path(args[0])
|
||||
config = json.loads(config_path.read_text(encoding="utf-8"))
|
||||
progress_path = Path(config["progress_path"])
|
||||
result_path = Path(config["result_path"])
|
||||
cancel_path = Path(config["cancel_path"])
|
||||
|
||||
try:
|
||||
write_json(progress_path, {"factor": 0.0, "text": "Loading import modules..."})
|
||||
if config["command"] == "read_meta":
|
||||
result = read_meta(config, progress_path, cancel_path)
|
||||
elif config["command"] == "import_layers":
|
||||
@@ -257,7 +256,4 @@ def main():
|
||||
"traceback": traceback.format_exc(),
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
return 0
|
||||
|
||||
28
uv.lock
generated
28
uv.lock
generated
@@ -25,7 +25,7 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "bioxelnodes"
|
||||
version = "2.0.0"
|
||||
version = "2.0.2"
|
||||
source = { editable = "." }
|
||||
dependencies = [
|
||||
{ name = "h5py" },
|
||||
@@ -60,7 +60,7 @@ requires-dist = [
|
||||
{ name = "matplotlib", specifier = "==3.10.7" },
|
||||
{ name = "mrcfile", specifier = "==1.5.1" },
|
||||
{ name = "pyometiff", specifier = "==1.0.0" },
|
||||
{ name = "scipy", specifier = "==1.17.1" },
|
||||
{ name = "scipy", specifier = "==1.16.3" },
|
||||
{ name = "simpleitk", specifier = "==2.3.1" },
|
||||
{ name = "transforms3d", specifier = "==0.4.2" },
|
||||
]
|
||||
@@ -949,23 +949,23 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "scipy"
|
||||
version = "1.17.1"
|
||||
version = "1.16.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "numpy" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/7a/97/5a3609c4f8d58b039179648e62dd220f89864f56f7357f5d4f45c29eb2cc/scipy-1.17.1.tar.gz", hash = "sha256:95d8e012d8cb8816c226aef832200b1d45109ed4464303e997c5b13122b297c0", size = 30573822, upload-time = "2026-02-23T00:26:24.851Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0a/ca/d8ace4f98322d01abcd52d381134344bf7b431eba7ed8b42bdea5a3c2ac9/scipy-1.16.3.tar.gz", hash = "sha256:01e87659402762f43bd2fee13370553a17ada367d42e7487800bf2916535aecb", size = 30597883, upload-time = "2025-10-28T17:38:54.068Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/df/75/b4ce781849931fef6fd529afa6b63711d5a733065722d0c3e2724af9e40a/scipy-1.17.1-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:1f95b894f13729334fb990162e911c9e5dc1ab390c58aa6cbecb389c5b5e28ec", size = 31613675, upload-time = "2026-02-23T00:16:00.13Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f7/58/bccc2861b305abdd1b8663d6130c0b3d7cc22e8d86663edbc8401bfd40d4/scipy-1.17.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:e18f12c6b0bc5a592ed23d3f7b891f68fd7f8241d69b7883769eb5d5dfb52696", size = 28162057, upload-time = "2026-02-23T00:16:09.456Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/6d/ee/18146b7757ed4976276b9c9819108adbc73c5aad636e5353e20746b73069/scipy-1.17.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a3472cfbca0a54177d0faa68f697d8ba4c80bbdc19908c3465556d9f7efce9ee", size = 20334032, upload-time = "2026-02-23T00:16:17.358Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ec/e6/cef1cf3557f0c54954198554a10016b6a03b2ec9e22a4e1df734936bd99c/scipy-1.17.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:766e0dc5a616d026a3a1cffa379af959671729083882f50307e18175797b3dfd", size = 22709533, upload-time = "2026-02-23T00:16:25.791Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/4d/60/8804678875fc59362b0fb759ab3ecce1f09c10a735680318ac30da8cd76b/scipy-1.17.1-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:744b2bf3640d907b79f3fd7874efe432d1cf171ee721243e350f55234b4cec4c", size = 33062057, upload-time = "2026-02-23T00:16:36.931Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/09/7d/af933f0f6e0767995b4e2d705a0665e454d1c19402aa7e895de3951ebb04/scipy-1.17.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43af8d1f3bea642559019edfe64e9b11192a8978efbd1539d7bc2aaa23d92de4", size = 35349300, upload-time = "2026-02-23T00:16:49.108Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/b4/3d/7ccbbdcbb54c8fdc20d3b6930137c782a163fa626f0aef920349873421ba/scipy-1.17.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cd96a1898c0a47be4520327e01f874acfd61fb48a9420f8aa9f6483412ffa444", size = 35127333, upload-time = "2026-02-23T00:17:01.293Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/e8/19/f926cb11c42b15ba08e3a71e376d816ac08614f769b4f47e06c3580c836a/scipy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4eb6c25dd62ee8d5edf68a8e1c171dd71c292fdae95d8aeb3dd7d7de4c364082", size = 37741314, upload-time = "2026-02-23T00:17:12.576Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/95/da/0d1df507cf574b3f224ccc3d45244c9a1d732c81dcb26b1e8a766ae271a8/scipy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:d30e57c72013c2a4fe441c2fcb8e77b14e152ad48b5464858e07e2ad9fbfceff", size = 36607512, upload-time = "2026-02-23T00:17:23.424Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/68/7f/bdd79ceaad24b671543ffe0ef61ed8e659440eb683b66f033454dcee90eb/scipy-1.17.1-cp311-cp311-win_arm64.whl", hash = "sha256:9ecb4efb1cd6e8c4afea0daa91a87fbddbce1b99d2895d151596716c0b2e859d", size = 24599248, upload-time = "2026-02-23T00:17:34.561Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/9b/5f/6f37d7439de1455ce9c5a556b8d1db0979f03a796c030bafdf08d35b7bf9/scipy-1.16.3-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:40be6cf99e68b6c4321e9f8782e7d5ff8265af28ef2cd56e9c9b2638fa08ad97", size = 36630881, upload-time = "2025-10-28T17:31:47.104Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7c/89/d70e9f628749b7e4db2aa4cd89735502ff3f08f7b9b27d2e799485987cd9/scipy-1.16.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:8be1ca9170fcb6223cc7c27f4305d680ded114a1567c0bd2bfcbf947d1b17511", size = 28941012, upload-time = "2025-10-28T17:31:53.411Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a8/a8/0e7a9a6872a923505dbdf6bb93451edcac120363131c19013044a1e7cb0c/scipy-1.16.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:bea0a62734d20d67608660f69dcda23e7f90fb4ca20974ab80b6ed40df87a005", size = 20931935, upload-time = "2025-10-28T17:31:57.361Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/bd/c7/020fb72bd79ad798e4dbe53938543ecb96b3a9ac3fe274b7189e23e27353/scipy-1.16.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:2a207a6ce9c24f1951241f4693ede2d393f59c07abc159b2cb2be980820e01fb", size = 23534466, upload-time = "2025-10-28T17:32:01.875Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/be/a0/668c4609ce6dbf2f948e167836ccaf897f95fb63fa231c87da7558a374cd/scipy-1.16.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:532fb5ad6a87e9e9cd9c959b106b73145a03f04c7d57ea3e6f6bb60b86ab0876", size = 33593618, upload-time = "2025-10-28T17:32:06.902Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/ca/6e/8942461cf2636cdae083e3eb72622a7fbbfa5cf559c7d13ab250a5dbdc01/scipy-1.16.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:0151a0749efeaaab78711c78422d413c583b8cdd2011a3c1d6c794938ee9fdb2", size = 35899798, upload-time = "2025-10-28T17:32:12.665Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/79/e8/d0f33590364cdbd67f28ce79368b373889faa4ee959588beddf6daef9abe/scipy-1.16.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b7180967113560cca57418a7bc719e30366b47959dd845a93206fbed693c867e", size = 36226154, upload-time = "2025-10-28T17:32:17.961Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/39/c1/1903de608c0c924a1749c590064e65810f8046e437aba6be365abc4f7557/scipy-1.16.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:deb3841c925eeddb6afc1e4e4a45e418d19ec7b87c5df177695224078e8ec733", size = 38878540, upload-time = "2025-10-28T17:32:23.907Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f1/d0/22ec7036ba0b0a35bccb7f25ab407382ed34af0b111475eb301c16f8a2e5/scipy-1.16.3-cp311-cp311-win_amd64.whl", hash = "sha256:53c3844d527213631e886621df5695d35e4f6a75f620dca412bcd292f6b87d78", size = 38722107, upload-time = "2025-10-28T17:32:29.921Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/60/8a00e5a524bb3bf8898db1650d350f50e6cffb9d7a491c561dc9826c7515/scipy-1.16.3-cp311-cp311-win_arm64.whl", hash = "sha256:9452781bd879b14b6f055b26643703551320aa8d79ae064a71df55c00286a184", size = 25506272, upload-time = "2025-10-28T17:32:34.577Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user