Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1350bbfb36 | ||
|
|
d216bdf138 |
73
AGENTS.md
73
AGENTS.md
@@ -1,3 +1,63 @@
|
|||||||
|
# Bioxel Nodes
|
||||||
|
|
||||||
|
## 项目概览
|
||||||
|
|
||||||
|
Bioxel Nodes 是一个基于 Blender 的科学体数据可视化插件,利用 Blender 自带的 Geometry Nodes 与 Cycles(同时支持 EEVEE NEXT)处理并渲染体数据。
|
||||||
|
|
||||||
|
- 支持格式:`.dcm`、`.tif`/`.tiff`、`.nii`/`.nii.gz`、`.nrrd`、`.ome.tiff`、`.mrc`、`.h5` 等,完整列表见 `src/bioxelnodes/bioxel/data.py` 的 `SUPPORT_EXTS`
|
||||||
|
- 支持 4D 体数据(多帧 / 多通道 / 时间序列)
|
||||||
|
- v2.0.x 仅支持 Blender 5.0+
|
||||||
|
- 核心依赖:SimpleITK、pyometiff、mrcfile、h5py、numpy、scipy、transforms3d、matplotlib
|
||||||
|
|
||||||
|
## 构建、测试与开发命令
|
||||||
|
|
||||||
|
- 环境:Python 3.11,依赖由 uv 管理(`uv.lock`)
|
||||||
|
- `uv sync` 安装 / 同步依赖
|
||||||
|
- `uv run pytest` 运行测试(当前暂无测试用例)
|
||||||
|
- `uv run mkdocs serve` 本地预览文档;`uv run mkdocs build` 构建到 `site/`
|
||||||
|
- `uv run mike deploy <version> -p` 发布版本化文档
|
||||||
|
- `uv run build.py <platform> 3.11` 下载第三方 wheel 并更新 `src/bioxelnodes/blender_manifest.toml`,`platform` 取 `windows-x64` / `linux-x64` / `macos-arm64` / `macos-x64`
|
||||||
|
- `python pack.py <platform> [output.zip]` 将 `src/bioxelnodes` 打包为 zip
|
||||||
|
- 发布:推送 `v*` 标签触发 `.github/workflows/release.yml`,产物命名 `BioxelNodes.<version>.<platform>.zip`
|
||||||
|
|
||||||
|
## 架构
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/bioxelnodes/ 插件包根目录
|
||||||
|
├── __init__.py 入口:register/unregister、CLI 命令与 WindowManager 属性
|
||||||
|
├── auto_load.py 自动发现并按拓扑排序注册 bpy 类
|
||||||
|
├── constants.py 常量(节点库路径等)
|
||||||
|
├── preferences.py AddonPreferences(缓存目录)
|
||||||
|
├── props.py PropertyGroup / UIList / 属性更新回调
|
||||||
|
├── menus.py 菜单与右键菜单
|
||||||
|
├── panels.py 面板
|
||||||
|
├── asset_library.py "O Bioxel" 资产库管理
|
||||||
|
├── node.py 节点组加载与添加
|
||||||
|
├── layer.py VDB 缓存、快照、图层元数据(text datablock JSON)
|
||||||
|
├── utils.py 通用工具(进度、对象查找、驱动等)
|
||||||
|
├── exceptions.py 向后兼容占位(自定义异常已改用内置异常)
|
||||||
|
├── blender_manifest.toml Blender 扩展清单
|
||||||
|
├── assets/O_Bioxel/ 节点库 .blend 与资产目录
|
||||||
|
├── wheels/ 随扩展分发的第三方 wheel
|
||||||
|
├── bioxel/ 核心数据模型(不依赖 Blender)
|
||||||
|
│ ├── data.py Data 类与解析(read / read_meta)
|
||||||
|
│ ├── parse.py 解析函数(parse_volumetric_data 等)
|
||||||
|
│ ├── layer.py Layer:TXYZC 顺序 ndarray + affine 变换
|
||||||
|
│ ├── container.py Container:name + layers
|
||||||
|
│ └── io.py HDF5 读写 Container
|
||||||
|
└── operators/ Operator 实现
|
||||||
|
├── io.py 导入 / 导出算子,启动后台导入进程
|
||||||
|
├── io_worker.py 后台 CLI 导入 worker(bioxelnodes_import_worker)
|
||||||
|
├── layer.py 图层管理算子
|
||||||
|
├── node.py AddNode
|
||||||
|
├── structure.py ExtractMesh
|
||||||
|
└── misc.py 杂项算子
|
||||||
|
```
|
||||||
|
|
||||||
|
数据流:导入时主进程通过 `operators/io.py` 启动一个后台 Blender 子进程(`blender --background --command bioxelnodes_import_worker`),由 `io_worker.py` 解析数据、生成 `Layer`,写为 VDB 缓存,并通过 JSON 文件(`progress.json` / `result.json` / `cancel`)回传进度与结果,避免阻塞 UI。
|
||||||
|
|
||||||
|
仓库根目录另有 `docs/`(mkdocs-material 文档,中英双语)、`openspec/`(spec-driven 变更流程)、`.agents/`(技能定义)。
|
||||||
|
|
||||||
## 总规范
|
## 总规范
|
||||||
|
|
||||||
- 说明性内容(例如提交说明、文档、注释、mermaid),以中文为主,专有名词、约定俗称可用英文
|
- 说明性内容(例如提交说明、文档、注释、mermaid),以中文为主,专有名词、约定俗称可用英文
|
||||||
@@ -17,3 +77,16 @@
|
|||||||
- 使用的依赖越少越好
|
- 使用的依赖越少越好
|
||||||
- 选用简单直接的方式实现
|
- 选用简单直接的方式实现
|
||||||
- 代码、执行方式改变,调整已有的文档、计划,而非新建
|
- 代码、执行方式改变,调整已有的文档、计划,而非新建
|
||||||
|
|
||||||
|
## Shell 规范
|
||||||
|
|
||||||
|
- 优先使用、提供 Git Bash 执行所有 Shell 命令
|
||||||
|
- Windows 路径在 Bash 命令中优先使用正斜杠形式
|
||||||
|
|
||||||
|
## Blender 开发规范
|
||||||
|
|
||||||
|
- 插件、资产库压缩包名用大驼峰,如果需要,用`b45`来表示适用blender版本。比如`OmooLab.v0.1.0.b45.zip`
|
||||||
|
- Operator、Menu、Panel、AddonPreferences... Class 用大驼峰命名,不加任何前缀。Operator 动宾结构,比如`RenderImage`。Menu、Panel 以它们本身为后缀,比如`RenderPanel`
|
||||||
|
- 根据项目名提炼项目缩写,作为 bl_idname 和 自定义 Property 的前缀以区分其他功能和属性,以`Omoo`为例
|
||||||
|
- bl_idname 用下划线小写命名,Operator 的 bl_idname 以`omoo.*`为前缀,比如`omoo.render_panel`;Menu 的以`OMOO_MT_*`为前缀;Panel 的以`OMOO_PT_*`为前缀。比如`OMOO_PT_render_panel`
|
||||||
|
- 自定义 Property 用下划线小写命名,以`omoo_*`为前缀。比如`omoo_progress_factor`
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
[project]
|
[project]
|
||||||
name = "bioxelnodes"
|
name = "bioxelnodes"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
description = ""
|
description = ""
|
||||||
authors = [{ name = "MaNan", email = "icrdr2010@outlook.com" }]
|
authors = [{ name = "MaNan", email = "icrdr2010@outlook.com" }]
|
||||||
requires-python = ">=3.11.0,<3.12.dev0"
|
requires-python = ">=3.11.0,<3.12.dev0"
|
||||||
@@ -18,7 +18,7 @@ dependencies = [
|
|||||||
|
|
||||||
[dependency-groups]
|
[dependency-groups]
|
||||||
dev = [
|
dev = [
|
||||||
"bpy>=4.2.0,<5",
|
"bpy==5.0.0",
|
||||||
"pytest>=8.3.2,<9",
|
"pytest>=8.3.2,<9",
|
||||||
"pytest-dependency>=0.6.0,<0.7",
|
"pytest-dependency>=0.6.0,<0.7",
|
||||||
"pytest-cov>=5.0.0,<6",
|
"pytest-cov>=5.0.0,<6",
|
||||||
|
|||||||
@@ -1,10 +1,20 @@
|
|||||||
import bpy
|
import bpy
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from .constants import NODE_LIB_DIRPATH
|
from .constants import LATEST_NODE_LIB_PATH, NODE_LIB_DIRPATH, NODE_LIB_FILENAME
|
||||||
|
|
||||||
|
|
||||||
ASSET_LIBRARY_NAME = "O Bioxel"
|
ASSET_LIBRARY_NAME = "O Bioxel"
|
||||||
|
ASSET_LIBRARY_READY = "READY"
|
||||||
|
ASSET_LIBRARY_OUTDATED = "OUTDATED"
|
||||||
|
ASSET_LIBRARY_MISSING = "MISSING"
|
||||||
|
|
||||||
|
STATUS_MESSAGES = {
|
||||||
|
"missing": "O Bioxel asset library is not installed.",
|
||||||
|
"missing_blend": "O Bioxel node library file is missing.",
|
||||||
|
"outdated": "O Bioxel node library needs update.",
|
||||||
|
"ready": "O Bioxel asset library is ready.",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def _asset_library_path():
|
def _asset_library_path():
|
||||||
@@ -19,6 +29,26 @@ def _asset_libraries():
|
|||||||
return bpy.context.preferences.filepaths.asset_libraries
|
return bpy.context.preferences.filepaths.asset_libraries
|
||||||
|
|
||||||
|
|
||||||
|
def _find_bioxel_asset_library():
|
||||||
|
lib_path = _normalized_path(_asset_library_path())
|
||||||
|
named_lib = None
|
||||||
|
|
||||||
|
for lib in _asset_libraries():
|
||||||
|
try:
|
||||||
|
if _normalized_path(lib.path) == lib_path:
|
||||||
|
return lib
|
||||||
|
if lib.name == ASSET_LIBRARY_NAME:
|
||||||
|
named_lib = lib
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
|
||||||
|
return named_lib
|
||||||
|
|
||||||
|
|
||||||
|
def _node_lib_path_for_library(lib):
|
||||||
|
return _normalized_path(lib.path) / NODE_LIB_FILENAME
|
||||||
|
|
||||||
|
|
||||||
def get_bioxel_asset_library():
|
def get_bioxel_asset_library():
|
||||||
lib_path = _normalized_path(_asset_library_path())
|
lib_path = _normalized_path(_asset_library_path())
|
||||||
|
|
||||||
@@ -32,16 +62,47 @@ def get_bioxel_asset_library():
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def get_bioxel_asset_library_status():
|
||||||
|
lib = _find_bioxel_asset_library()
|
||||||
|
lib_path = _normalized_path(_asset_library_path())
|
||||||
|
|
||||||
|
if lib is None:
|
||||||
|
return {"code": ASSET_LIBRARY_MISSING, "reason": "missing",
|
||||||
|
"message": STATUS_MESSAGES["missing"]}
|
||||||
|
|
||||||
|
try:
|
||||||
|
installed_lib_path = _normalized_path(lib.path)
|
||||||
|
except Exception:
|
||||||
|
return {"code": ASSET_LIBRARY_MISSING, "reason": "missing",
|
||||||
|
"message": STATUS_MESSAGES["missing"]}
|
||||||
|
|
||||||
|
if not _node_lib_path_for_library(lib).is_file():
|
||||||
|
return {"code": ASSET_LIBRARY_MISSING, "reason": "missing_blend",
|
||||||
|
"message": STATUS_MESSAGES["missing_blend"]}
|
||||||
|
|
||||||
|
if installed_lib_path != lib_path:
|
||||||
|
return {"code": ASSET_LIBRARY_OUTDATED, "reason": "outdated",
|
||||||
|
"message": STATUS_MESSAGES["outdated"]}
|
||||||
|
|
||||||
|
return {"code": ASSET_LIBRARY_READY, "reason": "ready",
|
||||||
|
"message": STATUS_MESSAGES["ready"]}
|
||||||
|
|
||||||
|
|
||||||
def has_bioxel_asset_library():
|
def has_bioxel_asset_library():
|
||||||
return get_bioxel_asset_library() is not None
|
return get_bioxel_asset_library_status()["code"] in {
|
||||||
|
ASSET_LIBRARY_READY,
|
||||||
|
ASSET_LIBRARY_OUTDATED,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
def add_bioxel_asset_library():
|
def add_bioxel_asset_library():
|
||||||
if not NODE_LIB_DIRPATH.exists():
|
if not NODE_LIB_DIRPATH.exists():
|
||||||
raise FileNotFoundError(f"Node library path does not exist: {NODE_LIB_DIRPATH}")
|
raise FileNotFoundError(f"Node library path does not exist: {NODE_LIB_DIRPATH}")
|
||||||
|
if not LATEST_NODE_LIB_PATH.is_file():
|
||||||
|
raise FileNotFoundError(f"Node library file does not exist: {LATEST_NODE_LIB_PATH}")
|
||||||
|
|
||||||
prefs = _asset_libraries()
|
prefs = _asset_libraries()
|
||||||
lib = get_bioxel_asset_library()
|
lib = _find_bioxel_asset_library()
|
||||||
|
|
||||||
if lib is None:
|
if lib is None:
|
||||||
for item in prefs:
|
for item in prefs:
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
schema_version = "1.0.0"
|
schema_version = "1.0.0"
|
||||||
|
|
||||||
id = "bioxelnodes"
|
id = "bioxelnodes"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
name = "Bioxel Nodes"
|
name = "Bioxel Nodes"
|
||||||
tagline = "For scientific volumetric data visualization in Blender"
|
tagline = "For scientific volumetric data visualization in Blender"
|
||||||
maintainer = "Nan <icrdr2010@outlook.com>"
|
maintainer = "Nan <icrdr2010@outlook.com>"
|
||||||
|
|||||||
@@ -89,7 +89,7 @@ def start_worker_process(owner, command: str, payload: dict):
|
|||||||
write_worker_json(config_path, config)
|
write_worker_json(config_path, config)
|
||||||
write_worker_json(
|
write_worker_json(
|
||||||
progress_path,
|
progress_path,
|
||||||
{"factor": 0.0, "text": "Starting background Blender..."},
|
{"factor": 0.0, "text": "Starting..."},
|
||||||
)
|
)
|
||||||
|
|
||||||
print(f"Starting Bioxel worker with addon module: {addon_name}")
|
print(f"Starting Bioxel worker with addon module: {addon_name}")
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import shutil
|
|||||||
|
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
|
from ..asset_library import ASSET_LIBRARY_MISSING, get_bioxel_asset_library_status
|
||||||
from ..node import add_bioxel_node, get_layer_nodes, get_main_node_group
|
from ..node import add_bioxel_node, get_layer_nodes, get_main_node_group
|
||||||
from ..utils import refresh_bioxel_panels
|
from ..utils import refresh_bioxel_panels
|
||||||
from ..layer import get_layer_caches, set_layer_caches
|
from ..layer import get_layer_caches, set_layer_caches
|
||||||
@@ -91,6 +92,11 @@ class AddLayerNode(bpy.types.Operator):
|
|||||||
cache_id: bpy.props.StringProperty() # type: ignore # 图层ID
|
cache_id: bpy.props.StringProperty() # type: ignore # 图层ID
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
|
status = get_bioxel_asset_library_status()
|
||||||
|
if status["code"] == ASSET_LIBRARY_MISSING:
|
||||||
|
self.report({"ERROR"}, status["message"])
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
# 获取图层数据
|
# 获取图层数据
|
||||||
caches = get_layer_caches()
|
caches = get_layer_caches()
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,12 @@ import bpy
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import shutil
|
import shutil
|
||||||
|
|
||||||
from ..asset_library import add_bioxel_asset_library
|
from ..asset_library import (
|
||||||
|
ASSET_LIBRARY_OUTDATED,
|
||||||
|
ASSET_LIBRARY_READY,
|
||||||
|
add_bioxel_asset_library,
|
||||||
|
get_bioxel_asset_library_status,
|
||||||
|
)
|
||||||
from ..constants import LATEST_NODE_LIB_PATH
|
from ..constants import LATEST_NODE_LIB_PATH
|
||||||
from ..utils import (
|
from ..utils import (
|
||||||
get_all_layer_objs,
|
get_all_layer_objs,
|
||||||
@@ -138,9 +143,18 @@ class AddAssetLibrary(bpy.types.Operator):
|
|||||||
if area.type == "NODE_EDITOR":
|
if area.type == "NODE_EDITOR":
|
||||||
area.tag_redraw()
|
area.tag_redraw()
|
||||||
|
|
||||||
self.report({"INFO"}, "O Bioxel asset library is ready.")
|
status = get_bioxel_asset_library_status()
|
||||||
|
if status["code"] == ASSET_LIBRARY_READY:
|
||||||
|
self.report({"INFO"}, status["message"])
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
if status["code"] == ASSET_LIBRARY_OUTDATED:
|
||||||
|
self.report({"WARNING"}, status["message"])
|
||||||
|
return {"FINISHED"}
|
||||||
|
|
||||||
|
self.report({"ERROR"}, status["message"])
|
||||||
|
return {"CANCELLED"}
|
||||||
|
|
||||||
|
|
||||||
# 定义虚无化切换操作
|
# 定义虚无化切换操作
|
||||||
class TogglePhantom(bpy.types.Operator):
|
class TogglePhantom(bpy.types.Operator):
|
||||||
|
|||||||
@@ -1,7 +1,12 @@
|
|||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import bpy
|
import bpy
|
||||||
|
|
||||||
from .asset_library import has_bioxel_asset_library
|
from .asset_library import (
|
||||||
|
ASSET_LIBRARY_OUTDATED,
|
||||||
|
ASSET_LIBRARY_READY,
|
||||||
|
get_bioxel_asset_library_status,
|
||||||
|
has_bioxel_asset_library,
|
||||||
|
)
|
||||||
from .node import get_layer_nodes, get_main_node_group
|
from .node import get_layer_nodes, get_main_node_group
|
||||||
from .utils import load_icon
|
from .utils import load_icon
|
||||||
from .layer import get_layer_caches
|
from .layer import get_layer_caches
|
||||||
@@ -78,13 +83,23 @@ class HeaderPanel(bpy.types.Panel, BioxelPanelBase):
|
|||||||
|
|
||||||
def draw(self, context):
|
def draw(self, context):
|
||||||
layout = self.layout
|
layout = self.layout
|
||||||
|
status = get_bioxel_asset_library_status()
|
||||||
|
|
||||||
if not has_bioxel_asset_library():
|
if status["code"] == ASSET_LIBRARY_OUTDATED:
|
||||||
|
layout.operator(
|
||||||
|
AddAssetLibrary.bl_idname,
|
||||||
|
text="Update Nodes Library",
|
||||||
|
icon="ASSET_MANAGER",
|
||||||
|
)
|
||||||
|
layout.label(text=status["message"], icon="INFO")
|
||||||
|
|
||||||
|
elif status["code"] != ASSET_LIBRARY_READY:
|
||||||
layout.operator(
|
layout.operator(
|
||||||
AddAssetLibrary.bl_idname,
|
AddAssetLibrary.bl_idname,
|
||||||
text="Add Nodes Library",
|
text="Add Nodes Library",
|
||||||
icon="ASSET_MANAGER",
|
icon="ASSET_MANAGER",
|
||||||
)
|
)
|
||||||
|
layout.label(text=status["message"], icon="INFO")
|
||||||
return
|
return
|
||||||
|
|
||||||
layout.operator(
|
layout.operator(
|
||||||
|
|||||||
36
uv.lock
generated
36
uv.lock
generated
@@ -25,7 +25,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bioxelnodes"
|
name = "bioxelnodes"
|
||||||
version = "2.0.2"
|
version = "2.0.4"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "h5py" },
|
{ name = "h5py" },
|
||||||
@@ -68,7 +68,7 @@ requires-dist = [
|
|||||||
[package.metadata.requires-dev]
|
[package.metadata.requires-dev]
|
||||||
dev = [
|
dev = [
|
||||||
{ name = "autopep8", specifier = ">=2.3.1,<3" },
|
{ name = "autopep8", specifier = ">=2.3.1,<3" },
|
||||||
{ name = "bpy", specifier = ">=4.2.0,<5" },
|
{ name = "bpy", specifier = "==5.0.0" },
|
||||||
{ name = "mike", specifier = ">=2.1.2,<3" },
|
{ name = "mike", specifier = ">=2.1.2,<3" },
|
||||||
{ name = "mkdocs", specifier = ">=1.6.0,<2" },
|
{ name = "mkdocs", specifier = ">=1.6.0,<2" },
|
||||||
{ name = "mkdocs-click", specifier = ">=0.9.0" },
|
{ name = "mkdocs-click", specifier = ">=0.9.0" },
|
||||||
@@ -84,7 +84,7 @@ dev = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bpy"
|
name = "bpy"
|
||||||
version = "4.2.0"
|
version = "5.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cython" },
|
{ name = "cython" },
|
||||||
@@ -93,10 +93,10 @@ dependencies = [
|
|||||||
{ name = "zstandard" },
|
{ name = "zstandard" },
|
||||||
]
|
]
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/ea/5a/d085d433ad26687d7ba5be235c57679780a3b41316cd7ece1ee65694ebad/bpy-4.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e6e8857c9f483d42f5388642601080ad3e7488970cbc9e59efeedf4a8c26c90b", size = 207901162, upload-time = "2024-07-25T09:03:05.781Z" },
|
{ url = "https://files.pythonhosted.org/packages/88/6c/87bd36315453b9a82f6392c31ed3c6eb504dfda4b591a0ca9b3a29715d07/bpy-5.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4a64f8862b29cc21358666d3b790fdf22060fe57e4626b3a8e1a879a8fecf961", size = 228454431, upload-time = "2025-11-18T17:09:51.446Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/39/03/579ec8a0d592424bd5743138ff40f2eca1944e427546721cfff091dbe730/bpy-4.2.0-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:4fd0e9872dceb37209d298ccbe77e6c3d0421501ef71b464dde22d09607966ec", size = 220963874, upload-time = "2024-07-25T09:05:08.352Z" },
|
{ url = "https://files.pythonhosted.org/packages/72/92/8b830f3f0cf8e548b2ac385c4a255aabb6b9e7dadde8149d7790ca296ab4/bpy-5.0.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:57804ccf770052a47e02f161d8a4401d93a2b1c120ff3ce9f8617466e55691f9", size = 382627218, upload-time = "2025-11-18T17:09:23.339Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/bc/5245f98dafa39166a4d4701d64077d281a36110e780011de5c38135089aa/bpy-4.2.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:a8217c2bd7b3424d1f51ce0698c0bf65439de352f7f6ed7b9942e2a9e5eb121b", size = 519384061, upload-time = "2024-07-25T09:04:30.48Z" },
|
{ url = "https://files.pythonhosted.org/packages/ae/01/bd9dc9806d5320a2caa4ad4f43ffdeebf70f8c398686d50d498a17de92b5/bpy-5.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:7b8b14b21006a487db88ff817eeb2d635073c24a8fb191b25c71b401641e1eaa", size = 340851458, upload-time = "2025-11-18T17:08:27.098Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c4/b0/6f18776208e13acb9bdbf3b5df9db9de42b09ab096aae68b171db422cccb/bpy-4.2.0-cp311-cp311-win_amd64.whl", hash = "sha256:26ce6210deb8316816938cb1c62c7fd257a8ef38d0c20b9f031a7a47a1492cac", size = 315442011, upload-time = "2024-07-25T09:03:45.29Z" },
|
{ url = "https://files.pythonhosted.org/packages/56/15/fe803465ecd93da65bb6900f7feb7e93a767d7b84a865a4b0882a0c27155/bpy-5.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:19d0922b5e1b62852fd826cf85e78a86324d3360cf1bda0bb5fb41c82005cb7c", size = 201997189, upload-time = "2025-11-18T17:08:45.541Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -674,20 +674,18 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "numpy"
|
name = "numpy"
|
||||||
version = "2.0.1"
|
version = "1.26.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/1c/8a/0db635b225d2aa2984e405dc14bd2b0c324a0c312ea1bc9d283f2b83b038/numpy-2.0.1.tar.gz", hash = "sha256:485b87235796410c3519a699cfe1faab097e509e90ebb05dcd098db2ae87e7b3", size = 18872007, upload-time = "2024-07-21T13:49:20.698Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/65/6e/09db70a523a96d25e115e71cc56a6f9031e7b8cd166c1ac8438307c14058/numpy-1.26.4.tar.gz", hash = "sha256:2a02aba9ed12e4ac4eb3ea9421c420301a0c6460d9830d74a9df87efa4912010", size = 15786129, upload-time = "2024-02-06T00:26:44.495Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/29/d6/ff66f4f87518a435538e15cc9e0477a88398512a18783e748914f0daf5ea/numpy-2.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:75b4e316c5902d8163ef9d423b1c3f2f6252226d1aa5cd8a0a03a7d01ffc6268", size = 21238269, upload-time = "2024-07-21T13:33:30.438Z" },
|
{ url = "https://files.pythonhosted.org/packages/11/57/baae43d14fe163fa0e4c47f307b6b2511ab8d7d30177c491960504252053/numpy-1.26.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4c66707fabe114439db9068ee468c26bbdf909cac0fb58686a42a24de1760c71", size = 20630554, upload-time = "2024-02-05T23:51:50.149Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c5/64/853cfc37494471e64ea9f7bf3bc3b4bb39450e6db5beeb05e2a66beef612/numpy-2.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6e4eeb6eb2fced786e32e6d8df9e755ce5be920d17f7ce00bc38fcde8ccdbf9e", size = 13334324, upload-time = "2024-07-21T13:33:51.455Z" },
|
{ url = "https://files.pythonhosted.org/packages/1a/2e/151484f49fd03944c4a3ad9c418ed193cfd02724e138ac8a9505d056c582/numpy-1.26.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:edd8b5fe47dab091176d21bb6de568acdd906d1887a4584a15a9a96a1dca06ef", size = 13997127, upload-time = "2024-02-05T23:52:15.314Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d1/d8/597b4b2e396a77cbec677c9de33bb1789d5c3b66d653cb723d00eb331e99/numpy-2.0.1-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:a1e01dcaab205fbece13c1410253a9eea1b1c9b61d237b6fa59bcc46e8e89343", size = 5298376, upload-time = "2024-07-21T13:34:01.627Z" },
|
{ url = "https://files.pythonhosted.org/packages/79/ae/7e5b85136806f9dadf4878bf73cf223fe5c2636818ba3ab1c585d0403164/numpy-1.26.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7ab55401287bfec946ced39700c053796e7cc0e3acbef09993a9ad2adba6ca6e", size = 14222994, upload-time = "2024-02-05T23:52:47.569Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/58/8664ff3747ac719ae1a5b9c0020533435158180a27f2f88a2b7a253bb623/numpy-2.0.1-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a8fc2de81ad835d999113ddf87d1ea2b0f4704cbd947c948d2f5513deafe5a7b", size = 6903817, upload-time = "2024-07-21T13:34:13.878Z" },
|
{ url = "https://files.pythonhosted.org/packages/3a/d0/edc009c27b406c4f9cbc79274d6e46d634d139075492ad055e3d68445925/numpy-1.26.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:666dbfb6ec68962c033a450943ded891bed2d54e6755e35e5835d63f4f6931d5", size = 18252005, upload-time = "2024-02-05T23:53:15.637Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/44/71ac0090d4ccb512fcac0ef0e5208248423a1ce30381541700470ac09b75/numpy-2.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3d94942c331dd4e0e1147f7a8699a4aa47dffc11bf8a1523c12af8b2e91bbe", size = 13916254, upload-time = "2024-07-21T13:34:35.466Z" },
|
{ url = "https://files.pythonhosted.org/packages/09/bf/2b1aaf8f525f2923ff6cfcf134ae5e750e279ac65ebf386c75a0cf6da06a/numpy-1.26.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:96ff0b2ad353d8f990b63294c8986f1ec3cb19d749234014f4e7eb0112ceba5a", size = 13885297, upload-time = "2024-02-05T23:53:42.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ef/27/39622993e8688a1f05898a3c3b2836b856f79c06637ebd4b71cb35cc9b18/numpy-2.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15eb4eca47d36ec3f78cde0a3a2ee24cf05ca7396ef808dda2c0ddad7c2bde67", size = 19540260, upload-time = "2024-07-21T13:35:09.114Z" },
|
{ url = "https://files.pythonhosted.org/packages/df/a0/4e0f14d847cfc2a633a1c8621d00724f3206cfeddeb66d35698c4e2cf3d2/numpy-1.26.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:60dedbb91afcbfdc9bc0b1f3f402804070deed7392c23eb7a7f07fa857868e8a", size = 18093567, upload-time = "2024-02-05T23:54:11.696Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6a/26/a32b5a6b3f090860aeefb3619bfea09f717d73908bd65e69e8ab0cac9c07/numpy-2.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b83e16a5511d1b1f8a88cbabb1a6f6a499f82c062a4251892d9ad5d609863fb7", size = 19938602, upload-time = "2024-07-21T13:35:38.996Z" },
|
{ url = "https://files.pythonhosted.org/packages/d2/b7/a734c733286e10a7f1a8ad1ae8c90f2d33bf604a96548e0a4a3a6739b468/numpy-1.26.4-cp311-cp311-win32.whl", hash = "sha256:1af303d6b2210eb850fcf03064d364652b7120803a0b872f5211f5234b399f20", size = 5968812, upload-time = "2024-02-05T23:54:26.453Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/34/b6/a88a9953d0be231c67aa0b3714d6138507490753beaa927f0b33f20cdca2/numpy-2.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f87fec1f9bc1efd23f4227becff04bd0e979e23ca50cc92ec88b38489db3b55", size = 14425300, upload-time = "2024-07-21T13:36:01.419Z" },
|
{ url = "https://files.pythonhosted.org/packages/3f/6b/5610004206cf7f8e7ad91c5a85a8c71b2f2f8051a0c0c4d5916b76d6cbb2/numpy-1.26.4-cp311-cp311-win_amd64.whl", hash = "sha256:cd25bcecc4974d09257ffcd1f098ee778f7834c3ad767fe5db785be9a4aa9cb2", size = 15811913, upload-time = "2024-02-05T23:54:53.933Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/e2/e763e102bea9c188b43ea144a91c22bec669736889a6e0be0235d64666d7/numpy-2.0.1-cp311-cp311-win32.whl", hash = "sha256:36d3a9405fd7c511804dc56fc32974fa5533bdeb3cd1604d6b8ff1d292b819c4", size = 6467652, upload-time = "2024-07-21T13:36:13.469Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/67/928e8f0d5c7fd32f32fb5caf92b186a1b3826dbaf5a294e13a976d6c38b6/numpy-2.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:08458fbf403bff5e2b45f08eda195d4b0c9b35682311da5a5a0a0925b11b9bd8", size = 16559280, upload-time = "2024-07-21T13:36:44.641Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
Reference in New Issue
Block a user