Metadata-Version: 2.5
Name: linshu-format
Version: 1.0.1
Summary: 通用层次化脑机接口数据容器格式
Requires-Python: >=3.10
Requires-Dist: dask
Requires-Dist: neo
Requires-Dist: numcodecs
Requires-Dist: numpy
Requires-Dist: pandas
Requires-Dist: pydantic>=2.0
Requires-Dist: spikeinterface
Requires-Dist: xarray
Requires-Dist: zarr<4,>=2.18
Provides-Extra: dev
Requires-Dist: pynwb==3.1.3; extra == 'dev'
Requires-Dist: pytest; extra == 'dev'
Requires-Dist: pytest-asyncio; extra == 'dev'
Provides-Extra: nwb
Requires-Dist: pynwb<4,>=3.1.3; extra == 'nwb'
Description-Content-Type: text/markdown

# Linshu 自有格式

面向侵入式、半侵入式、非侵入式脑机接口数据的通用容器格式标准。

## 定位

Linshu 自有格式是完全自全的通用层次化数据容器，借鉴 NWB 的程序设计理念并进行现代化重构，致力于取代 NWB。

Linshu 提供 S3 云存储、Zarr v2/v3 自适应、pydantic 类型安全等现代化能力。

## 格式要求

1. 支持对象存储，S3协议，尽可能兼容云、分布式处理。
2. Python友好，pythonic编程实现。
3. 可完整承载 NWB 文件作为数据单元，支持与 pynwb 互操作。
4. 支持软链接：文件的某个字段可指向另一个完整Linshu文件。打开父文件时不立即加载外部数据，用户访问该字段时触发按需读取。大数据与元数据分离存储由用户自行决策，Linshu提供功能保障。
5. 数据格式及大多数函数方法、类可以通过mypy、pyright直接从代码进行静态推断，代码即格式。
6. 实现高并发、细粒度的IO操作，支持zarr局部修改写入。

## 数据字段类型与 Zarr 映射

| 字段类型 | Zarr 存储位置 | 说明 |
|---------|-------------|------|
| 字符串（含软链接路径） | Group attribute | `zarr.json` 的 attributes 字典 |
| 整型数字 | Group attribute | 同上 |
| 浮点数字 | Group attribute | 同上 |
| 布尔类型 | Group attribute | 同上 |
| 日期时间（Python datetime） | Group attribute | ISO 8601 字符串 |
| Numpy Array | Array | Zarr Array，chunk策略可配置 |
| Pandas Dataframe | Sub-group | 存储布局参数化：`row_wise`（按行组切块）用于行为/时间序列型数据；`column_wise`（每列一个Zarr Array）用于事件/变量型数据 |
| 嵌套 pydantic Model | Sub-group | 递归进入，其标量字段成为该 group 的 attribute |

## 相比于NWB作出的改变

- 代码即规范。
- 使用pydantic取代JSON schema、@register_class、__nwbfields__、@docval。
- 直接 Container 到存储的映射，消除Builder层，IO 后端对 zarr v2 / v3 自适应（行为矩阵见下文）。pydantic模型树定义规范结构，薄映射层遍历模型树按字段类型分派到Zarr原子操作；pydantic模型不承载序列化逻辑。读取采用代理对象惰性加载（打开文件仅解析根结构），写入仅更新实际变更部分。pydantic模型树层级直接映射为Zarr目录层级。
- 不支持用户弹性扩展规范。不提供YAML驱动类生成、NWBNamespaceBuilder、entry-point插件发现、命名空间注册表等形式化插件设施。规范升级通过pydantic Python类继承在内部完成，外部用户可通过fork仓库自行开发。
- 每个字段赋予全局唯一数值 ID（整个规范中所有类型的所有字段共享同一ID空间），构建时由工具自动生成并持久化于锁定文件。ID基于字段在模型树中的限定路径和名称确定性派生，字段位置与名称不变则ID跨版本保持一致。
- Linshu格式规范采用语义化版本（SemVer），记录于Zarr根group的attribute中。

## Zarr 版本行为矩阵（zarr v2 / v3 自适应）

Linshu 的 IO 层（`core/_zarr_compat.py` 门面）不写死 zarr 主版本，而是在运行时探测当前环境的 zarr 库，并按其能力读写对应格式。行为取决于**运行环境的 zarr 版本**与**磁盘文件的格式**：

| 环境 | 默认写入格式 | 读取 v2 文件 | 读取 v3 文件 | 请求格式不可达时 |
|------|-------------|-------------|-------------|----------------|
| `zarr>=3`（如 3.2.1） | zarr v3（规范格式） | ✅ 自动探测，正常读回 | ✅ 正常读回 | 无（v3 环境两种格式均可） |
| `zarr==2.18.x` | zarr v2（写非规范格式，发 `UserWarning`） | ✅ 正常读回 | ❌ 主动抛 `ZarrFormatError` | 请求 `zarr_format=3` → `ZarrFormatError` |

要点：

- **默认写格式 = 当前环境原生格式**。zarr v3 环境下默认写出规范格式 v3；zarr v2 环境下默认写出 v2，并发出 `UserWarning` 提示当前环境无法产出规范格式。
- **读取自动探测**：v3 环境可读 v2 / v3 两种文件；v2 环境遇 v3 文件主动抛 `ZarrFormatError`（而非含糊的底层错误）。
- **原地写回保持来源格式**：`from_zarr` 读回时记录来源格式（`_source_format`），`write(inplace=True)` 保持该格式，绝不静默迁移。

### `zarr_format` 参数

`Model.write(path=..., zarr_format=...)` 接受 `None` / `2` / `3`：

- `None`：新路径 → 当前环境默认格式（v3 环境为 3，v2 环境为 2 并警告）；原地写回 → 保持来源格式。
- 显式 `2` / `3`：指定目标格式。原地写回且与来源格式不同时为**显式迁移**，发出 `UserWarning` 提示。
- 传非法值（如 `4`）→ `ValueError`（参数校验，两种库环境下行为一致）。
- zarr v2 环境请求 `zarr_format=3` → `ZarrFormatError`（当前环境无法读写 v3 格式的 store）。

### `ZarrFormatError`

`RuntimeError` 子类，表示目标 zarr 格式在当前环境不可达（如 zarr v2 环境请求 v3 格式）。消息包含当前 zarr 版本、被请求格式与解决办法。读取入口（`from_zarr`）与写入入口（`resolve_format`）均会触发该异常。

## TODOs

- 软链接支持
- 基于zarr的加密
- 提供对SpikeInterface的良好支持
