Metadata-Version: 2.4
Name: tsv-sdk-python
Version: 1.3.2
Summary: Python ctypes bindings for tsv-sdk
Author: TSV
License-Expression: LicenseRef-Proprietary
Keywords: tsv,ffi,laser,sdk
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: Microsoft :: Windows
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Programming Language :: Python :: 3 :: Only
Classifier: Topic :: Scientific/Engineering
Classifier: Topic :: Software Development :: Libraries :: Python Modules
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Provides-Extra: dev
Requires-Dist: build>=1.2; extra == "dev"
Requires-Dist: twine>=6.2; extra == "dev"

# TSV Python SDK 说明

本目录对应 TSV 线激光相机的 Python 接入方案，适合快速联调、算法验证、数据记录和轻量服务程序。

如果你是已经拿到交付包的最终用户，优先阅读交付包里的 README 和用户手册；这份仓库内文档更适合维护者、测试人员或需要直接从源码目录验证 Python 绑定的人。

## 适合什么场景

- 快速联调线激光相机
- 做算法验证、数据记录或结果抓取
- 希望用较少代码先跑通连接、参数读取和结果消费

如果只是第一次联调设备，建议先跑最小示例，先验证版本号、连接状态和首帧结果，再接入正式业务流程。

## 最小联调建议

推荐按下面顺序验证：

1. 打印 `version_str()` 和 `version_code()`。
2. 创建连接对象。
3. 启动数据传输。
4. 等待设备参数同步完成，并收到首帧结果。
5. 再读取曝光、激光和任务号等关键参数。
6. 最后停止传输并释放资源。

如果现场需要做快速验收，建议至少确认：能连上设备、能看到状态变化、能读到参数、能收到一帧有效结果、能正常停止并再次启动。

## 原生库查找顺序

绑定层会按以下顺序查找原生库：

1. `Client.connect(..., library_path=...)` 显式传入的路径
2. `TSV_FFI_LIB_PATH`
3. 已安装 Python 包内与当前架构匹配的 `tsv/native/<rid>`，例如 `tsv/native/win-x64`、`tsv/native/win-x86`、`tsv/native/linux-x64` 或 `tsv/native/linux-arm64`
4. 已安装 Python 包内的 `tsv/native`
5. `target/debug`
6. 当前工作目录
7. 平台默认动态库搜索路径

`library_path` 和 `TSV_FFI_LIB_PATH` 都可以指向具体库文件，也可以指向包含该库文件的目录。

如果程序运行时提示找不到 `tsv_ffi`，优先检查 `TSV_FFI_LIB_PATH`、工作目录以及是否加载到了其他位置的旧版原生库。

## 快速开始

```python
from tsv import Client

with Client.connect("192.168.3.123") as client:
    client.start()
    result = client.get_scan_result()
    print(result)
    client.stop()
```

## 运行示例

先构建原生库：

```bash
cargo build -p ffi
```

然后在工作区根目录运行示例：

```bash
PYTHONPATH=ffi/python python ffi/python/examples/basic.py 192.168.3.123
```

如果原生库不在默认搜索路径中，可显式指定：

```bash
export TSV_FFI_LIB_PATH=target/debug/libtsv_ffi.so
```

示例程序会执行以下流程：

- 打印 `version_str()` 和 `version_code()`
- 注册状态回调和扫描结果回调
- 启动数据流并等待设备参数同步完成
- 读取序列号、主控板 ID、曝光时间、激光参数和任务 ID
- 通过 `get_scan_result()` 轮询一帧最新结果
- 停止数据流并清除回调

可参考：

- `examples/basic.py`

## 构建与交付 Python 包

构建源码包和公共 wheel：

```bash
python -m build ffi/python --outdir dist/tsv-sdk-<version>/python
```

构建一个在打包时把原生库写入 `tsv/native` 的内部 wheel：

```bash
python -m tools.build package python-internal
```

内部 wheel 现在按单个 RID 构建，并产出与该 RID 对应的平台 wheel tag；默认使用当前主机对应的 RID，也可以通过 `--rid` 显式指定。Linux 下会通过 `auditwheel show` 自动把平台 tag 收敛到 PyPI 可接受的 `manylinux_*` 形式。release 模式下会把该 RID 的 `tsv_ffi` 与 `tsv_media` 一起打入 `tsv/native/<rid>/`。你也可以覆盖原生库来源，或直接选择单个文件/目录：

```bash
python -m tools.build package python-internal --configuration release
python -m tools.build package python-internal --configuration release --rid linux-arm64
python -m tools.build package python-internal --library target/debug
python -m tools.build package python-internal --library ./artifacts/libtsv_ffi.so
```

脚本会在打包完成后恢复 `tsv/native`，因此复制进去的原生库不会残留在工作树中。

校验生成出的元数据和长描述：

```bash
python -m pip install -e ffi/python[dev]
python -m twine check dist/tsv-sdk-<version>/python/*
```

如果你是从仓库根目录走统一发布入口，可在配置好 `TWINE_USERNAME` / `TWINE_PASSWORD` 或 `.pypirc` 后执行：

```bash
cargo make publish-pypi
```

该任务会重新构建公共 sdist、公共 wheel 和当前平台内部 wheel，并通过 `twine upload --skip-existing` 上传到 PyPI；因此同一版本可以在多台机器上重复执行，把不同平台 wheel 逐步补齐。

## 分发说明

- 发布出来的公共 wheel 和内部 wheel 都声明支持 Python 3.10 到 3.14，并使用 `py3` wheel tag，因此不需要为每个 CPython 小版本单独出包。
- 对外发布的公共包仅包含 Python 绑定代码，不包含原生 `tsv_ffi` / `tsv_media` 库
- 应用侧需要单独分发原生库，并通过 `TSV_FFI_LIB_PATH`、自定义 `library_path` 或受支持的动态库搜索路径暴露给绑定层
- 源码包中会包含示例脚本，便于使用者参考

## 推荐的原生库交付策略

对于内部交付，推荐使用以下两种布局之一：

1. 应用本地部署：把 `tsv_ffi` 与同平台的 `tsv_media` 放到应用入口附近，再通过显式 `library_path` 或 `TSV_FFI_LIB_PATH` 让绑定层找到它们
2. 包内部署：在构建 wheel 之前先把 `tsv_ffi` 与同平台的 `tsv_media` 放到 `tsv/native/` 下，安装后绑定层会自动发现它们

第二种方式适合通过私有制品库分发内部 wheel。当前公共 Python 包元数据已经配置为：只要构建时存在 `tsv/native/*.dll`、`tsv/native/*/*.dll`、`*.so` 或 `*.dylib`，就会把它们纳入打包范围。

`python -m tools.build package python-internal` 已经把这套流程自动化：它会先把单个 RID 对应的原生库暂存到 `tsv/native/<rid>`，在 `dist/tsv-sdk-<version>/python/internal` 下生成平台 wheel，然后恢复源代码目录；release 模式下也会自动把该 RID 对应的 `tsv_media` 一起打包进去。
