Metadata-Version: 2.4
Name: socbag-manager
Version: 0.0.7
Summary: 单帧 soc bag 目录的发现与路径解析（支持 multi/single 双格式），仅返回路径信息，不提供文件读写
License-Expression: MIT
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: PyYAML>=5.4.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"

# socbag-manager

单帧 soc bag 目录的**发现与路径解析**库，仅返回路径信息，不读取/写入文件内容。

## 版本与输入模式（V0.0.7）

| 模式 | 输入含义 | 目录结构 |
|------|----------|----------|
| **multi** | 多 `base_paths` + `bag_path` | `camera/{name}/data/{frame}.png`、`lidar/{name}/pcd/{frame}.pcd` |
| **single** | 单一路径（如 `.../static_data`）或 bag 根 | `camera/{sensor}_{frame}.png`、`lidar/{sensor}_{frame}.pcd`（平铺） |

通过配置 **input_mode: "multi" \| "single"** 决定使用哪套发现与解析逻辑，两种格式分别对应、互不混用。

- **multi**：与 V0.0.3/V0.0.4 一致，在多数据根下按 priority 查找同一 bag；子目录 `data`/`pcd`。
- **single**：将给定路径视为父目录时用 `discover_bags_under` 扫描其下符合约定的 soc 子目录；每个 bag 根内为**平铺文件**（如 `camera/front_120_000005.png`）。可选依赖 bag 根下 `extract_manifest.yaml`（`query_frame`、`extracted[].sensor/type`）做发现。

**single 目录示例**：`.../static_data/20260208-160115_soc2/` 下存在 `camera/front_120_000005.png`、`lidar/at128p_front_000005.pcd` 等；可含 `extract_manifest.yaml`。

V0.0.6 起，single 平铺帧号按数字等价匹配但保留真实文件帧号：用户传入 `5`、`000005` 或 `0000000005`，都可解析到磁盘上的 `front_120_0000000005.jpg`、`at128p_front_0000000005.pcd`；`discover_sequences_from_bag_root(..., layout="single")` 仍返回真实文件帧号。

V0.0.7 起，single 布局下即使 `extract_manifest.yaml` 只有 `query_frame` / `matched_frame_stems` / `copied_files` 而没有 `extracted` 列表，camera/lidar 发现与路径解析也会回退扫描 `camera/*.jpg|png`、`lidar/*.pcd`。

## 目录约定与 soc 规则

- **soc 规则**（multi/single 共用）：目录被视为 soc bag 当且仅当：**同时存在 `camera/` 与 `lidar/` 子目录，且该目录总大小 ≥ 阈值（默认 1MB）**。不依赖文件夹名；名称模式 `bag_name_pattern` 为可选过滤。
- **multi**：`{bag_root}/camera/{camera_name}/data/{sequence}.png`（或 .jpg），`{bag_root}/lidar/{lidar_name}/pcd/{sequence}.pcd`。
- **single**：`{bag_root}/camera/{sensor}_{frame}.png`，`{bag_root}/lidar/{sensor}_{frame}.pcd`。

## 安装

```bash
pip install socbag-manager
```

## 统一设置

所有 API 基于 `SocbagManagerSettings`，可从代码构造或 YAML 加载（兼容 C03 `base_paths`/`priority_base_path` 与 C04 `data_dirs`/`default_main_dir`）：

```python
from socbag_manager import SocbagManagerSettings

settings = SocbagManagerSettings(
    base_paths={"pandar": "/data/pandar", "at128": "/data/at128"},
    priority_source="pandar",
    bag_name_pattern="*_soc*",
    input_mode="multi",  # 或 "single"
)
# 或
settings = SocbagManagerSettings.from_yaml("/path/to/config.yaml")
```

## 主要 API

- **发现（multi）**: `get_ordered_base_paths`, `discover_bags`, `discover_bags_from_scan_root`, `discover_cameras`, `discover_lidars`, `discover_sequences`
- **发现（single）**: `discover_bags_under(parent_dir, bag_name_pattern="*_soc*", max_depth=1, min_size_mb=None)`；`discover_sequences_from_bag_root(bag_root, layout=...)`, `discover_cameras_from_bag_root`, `discover_lidars_from_bag_root`（传 `layout="single"` 或由 settings.input_mode 决定）
- **规则**：`is_soc_bag_dir(dir_path, min_size_mb)` — 判定目录是否符合 soc 解构
- **路径解析**: `resolve_camera_paths`, `resolve_lidar_paths`, `resolve_frame_paths`（按 input_mode 选 multi/single 路径）；`resolve_frame_paths_from_bag_root(bag_root, sequence, ..., layout=...)`
- **候选枚举**: `list_frame_candidates`, `choose_one_candidate`（`CandidatePath`）
- **目录树**: `TreeNode`, `build_folder_tree(settings, scope="roots"|"bags"|"sequences", ...)`

## 使用示例

### multi 模式

```python
from socbag_manager import (
    SocbagManagerSettings,
    discover_bags,
    discover_sequences,
    resolve_frame_paths,
    build_folder_tree,
)

settings = SocbagManagerSettings.from_yaml("config.yaml")
bag_names = discover_bags(settings)
sequences = discover_sequences(settings, bag_names[0])
paths = resolve_frame_paths(settings, bag_names[0], sequences[0])
# paths["images"], paths["pcds"]

tree_roots = build_folder_tree(settings, scope="bags")
```

### single 模式

```python
from socbag_manager import (
    SocbagManagerSettings,
    discover_bags_under,
    discover_sequences_from_bag_root,
    resolve_frame_paths_from_bag_root,
)

settings = SocbagManagerSettings(
    base_paths={"main": "/path/to/static_data_parent"},
    input_mode="single",
)
static_data_dir = "/media/mini/T9/03_single_frame/AB6_HW3_XZB600019/static_data"
bag_roots = discover_bags_under(static_data_dir, max_depth=1, min_size_mb=0)
for bag_root in bag_roots:
    sequences = discover_sequences_from_bag_root(bag_root, layout="single")
    if sequences:
        paths = resolve_frame_paths_from_bag_root(bag_root, sequences[0], layout="single")
        # paths["images"], paths["pcds"] 与 multi 格式一致
```

YAML 可选：`input_mode: single`、`static_data_dir: /path/to/static_data`（加载后可用 `discover_bags_under(settings.static_data_dir)`）。

## 约束

- 所有接口**仅返回路径**，不读取/解析图像或点云文件。
- 依赖：Python >=3.10，PyYAML。

## 开发与测试

```bash
pip install -e ".[dev]"
python -m pytest tests/ -v
```
