This release is a pre-release and may not be stable for production use.
SqlFileSystem v2 Python SDK
状态:活跃维护。 Python 是当前唯一开发、测试和发布的 SDK,将先在多个真实项目 中验证稳定性,再作为未来 Kotlin/Node.js SDK 的行为基准。
SDK 通过私有 ctypes 层调用 sfs-ffi ABI v2,同时提供同步 Sfs 和 asyncio
AsyncSfs。低层 C 结构、raw handle、伪流式接口及尚未完成验收的后端不会进入稳定
公共 API。
安装
PyPI 分发名为 sfs-v2(代码仍 import sfs)。与 PyPI 已有的其他项目 sfs 不同,勿同时安装二者。每个平台的 wheel 仅内嵌该平台的原生库,由 pip 自动选择:
pip install sfs-v2==0.0.1.dev1
首次发布仅提供 Windows x86_64 与 Linux x86_64;不要将只包含某平台原生库的 wheel 标记为 py3-none-any。Linux wheel 的 manylinux/glibc 最低要求以实际发布文件名为准。
源码开发时先构建 FFI,并让 SFS_NATIVE_PATH 指向产物:
cargo build --release -p sfs-ffi
# Linux/macOS
export SFS_NATIVE_PATH=../../target/release/libsfs_ffi.so
# Windows PowerShell
$env:SFS_NATIVE_PATH="..\..\target\release\sfs_ffi.dll"
加载时 SDK 会执行 ABI 版本和全部 C 结构尺寸握手;Python 包与动态库不匹配时会在 open 前明确报错,而不是继续错误解释内存。
同步 API
from sfs import Sfs, WriteItem
with Sfs.open_sqlite("/path/to/db") as store:
store.makedirs("/pages/2026")
store.write_text("/pages/2026/a.html", "<html>...</html>")
print(store.read_text("/pages/2026/a.html"))
store.write_many([
WriteItem("/pages/2026/b.html", b"..."),
WriteItem("/pages/2026/c.html", b"..."),
])
Sfs 会为每次操作取得生命周期 lease;close() 会阻止新操作并等待所有在途调用
结束,随后只释放一次原生 handle。close 后调用任何方法都会抛 SfsClosedError。
OpenOptions(readonly=True) 会以只读方式挂载已有字典用于解码,不训练或改写字典。
所需字典缺失/损坏时读取必须明确报错,不会把压缩 payload 当成文件内容返回。
asyncio API
from sfs import AsyncOptions, AsyncSfs
store = await AsyncSfs.open_sqlite(
"/path/to/db",
async_options=AsyncOptions(
queue_capacity=256,
max_queued_bytes=256 * 1024 * 1024,
write_batch_size=100,
flush_interval=0.05,
),
)
async with store:
await store.write("/result.bin", payload)
AsyncSfs 使用一个专用单线程 executor、有界队列、字节水位和单 writer 自动聚合并发
写请求。以下是稳定契约:
await write/write_many正常返回,表示底层同步批量写已经成功提交;- 仅进入 asyncio Queue 不会完成 Future;
- 同批失败会传播给该批全部等待者;
aclose()停止接收新任务、排空队列、等待原生调用,再关闭 handle;- 调用方取消等待、远程断线或提交 ACK 丢失时底层写可能仍已完成;这些情况的
outcome unknown,不表示“未写入”。只有
await正常返回才是 commit 成功 ACK。
分页与扫描
普通列表默认最多返回 1000 条;大目录优先使用惰性 iterator:
for info in store.iter_files("/pages", page_size=1000):
print(info.full_path)
扫描默认遇错中止,避免静默漏文件:
from sfs import ScanFilter, ScanOptions
with store.scan(ScanOptions(filter=ScanFilter(extensions=("html",)))) as scan:
for item in scan:
process(item.info, item.data)
asyncio 版本返回可显式关闭的 AsyncSfsScan,可读取最终统计和 Collect 错误:
scan = store.scan(ScanOptions(filter=ScanFilter(extensions=("html",))))
async with scan:
async for item in scan:
await process(item)
stats = await scan.stats()
errors = await scan.take_errors()
SDK 不提供 scan.to_list(),防止把大规模扫描结果全部装入内存。扫描事件携带完整
内容,因此单文件硬上限为 4 MiB;更大文件应改走分块读取。同步 SfsScan 与异步
AsyncSfsScan 都应显式使用 context manager;store close 也会等待仍活动的异步扫描
句柄关闭后再终止 executor。
错误
所有错误继承 SfsError,并携带稳定字段:
try:
store.read("/missing")
except SfsError as error:
print(error.code, error.operation, error.path, error.database_code, error.retryable)
常用子类包括 SfsNotFoundError、SfsDatabaseLockedError、
SfsCorruptDataError、SfsReadonlyError 和 SfsResourceExhaustedError。
维护与实验能力
空间回收不与常规读写平级:
report = store.maintenance.shrink()
if not report.succeeded:
print(report.vacuum_failed_volumes)
SDK 优先使用 optional sfs_shrink_v2 获取并释放 vacuum_failed_volumes;早期 ABI v2
缺少新符号时会回退 legacy 24-byte 报告,失败卷只能显示为空。需要完整维护诊断时应
使用当前 native。
PostgreSQL、MySQL 和远程 gRPC 入口尚未完成 Python 集成矩阵,只能显式从
sfs.experimental 导入,不属于当前兼容承诺。当前稳定支持范围仍是 SQLite;
Kotlin/Node.js SDK 继续封存。
远程连接可匿名,也可传 opaque bearer token:
import os
from sfs.experimental import connect_remote
store = connect_remote(
"http://127.0.0.1:50051",
token=os.environ.get("SFS_TOKEN"),
)
调用方传不含 scheme 的 opaque token;Python 不改写、不记录它,gRPC 适配器自动构造
authorization: Bearer <token> header。远程句柄直接复用现有 Sfs.scan();底层 ScanV2
会传输 COLLECT 错误并要求唯一 final stats,无需新增 remote scan API。远程 scan 的最低
协议要求是服务端同样实现当前 ScanV2;连接旧服务端收到 gRPC Unimplemented 时会映射
为 SfsUnsupportedError,不会保真假成功地回退到缺少 COLLECT errors/final stats 的
legacy scan。当前没有 Python 公开 stream/per-call-deadline API,也没有用于自签/私有 CA 的 Python 参数;
实验性 connect_remote("https://your-host:51337", token=...) 的 HTTPS endpoint 可直通
底层 gRPC 客户端,使用操作系统信任根验证证书链和主机名,不禁用 TLS 验证。此能力
尚不属于稳定远程 SDK API,私有/自签 CA 目前只能通过 Rust
GrpcClient::connect_with_auth_and_ca(endpoint, token, Some(ca_pem)) 显式配置。异步爬虫可用
async with await sfs.experimental.connect_remote_async(endpoint, token) as store:,其连接/读写在
专用单线程 executor 中执行,成功 await store.write(...) 才代表服务端写入已提交。
Rust 客户端为普通 unary RPC 设置默认 120 秒截止时间;爬虫进程可用环境变量
SFS_REMOTE_REQUEST_TIMEOUT_SECS=1..600 调整。超时的写入结果可能已经提交,
不能自动盲重试;流式传输尚无客户端完整/空闲截止时间。
SFS→PostgreSQL 是独立 TLS 链路:每个 SFS 进程的 PG DSN 指定 sslmode=require,驱动才强制 TLS、验证 CA 与服务器主机名;私有 CA 在 SFS 主机上用 SFS_PG_TLS_CA_FILE=/absolute/path/pg-ca.pem 指定(否则使用操作系统信任根),不要在爬虫进程设置 PG DSN 或分发数据库凭据。未指定 sslmode 或使用 prefer(SFS 的 prefer 不尝试 TLS)只有明确的数字回环 IP/Unix socket 才保留明文,远端/localhost 主机名将拒绝;可信隧道若确需明文须显式 sslmode=disable;sslmode=verify-full 和 sslrootcert 不是当前 tokio-postgres 可解析的 DSN 参数,SFS 的 require 明确执行更严格的完整证书/主机名验证;各业务/字典连接与异步连接池会固定打开时的 CA 信任配置,轮换 CA 后重启服务。直连 PG 的实验性 Python FFI 路径也遵守同一配置,但这不是推荐的多爬虫架构。
服务端内置 TLS 同时保护 HTTPS REST 与 gRPC(HTTP-only 模式也启用 HTTPS);
非 loopback 监听必须同时配置有效 bearer token 和 TLS PEM 证书/私钥,仅配置 token
不能使用明文监听。不得用 Python 示例经非 loopback 明文 HTTP 传 token。证书密钥文件
路径可通过 CLI --tls-cert / --tls-key(或环境变量 SFS_TLS_CERT /
SFS_TLS_KEY)成对传递;token 建议从安全秘密管理器注入 SFS_AUTH_TOKEN,勿写在
日志/源码/命令行。
容量边界必须区分:远程普通 read/write 受 300 MiB unary message ceiling 约束;底层 C 真流
(SQLite 本地与 gRPC 远程)单 chunk 最大 4 MiB、单文件最大 8 GiB。C 写流只有显式
flush/finish 成功才拿到 durable commit ACK;未 flush 直接 close 会 abort。由于 Python
尚未公开 stream wrapper,8 GiB 不是当前 Python 普通 read/write 的承诺。
测试
python -m pytest test_open_options.py test_sfs.py test_async_sfs.py -v
Release files for sfs-v2 0.0.1.dev1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sfs_v2-0.0.1.dev1-py3-none-win_amd64.whl | Python 3 | none | Windows x86-64 | Details |
| sfs_v2-0.0.1.dev1-py3-none-manylinux_2_28_x86_64.whl | Python 3 | none | Linux glibc 2.28+ x86-64 | Details |
Total release size: 10.1 MB
Release files / sfs_v2-0.0.1.dev1-py3-none-win_amd64.whl
| Download URL | sfs_v2-0.0.1.dev1-py3-none-win_amd64.whl |
|---|---|
| Size | 4.6 MB |
| Tags | Python 3 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
37f6a80a12ea8527555566b63eeb13711843dfa3a047b52406ebe75e0723a34f
|
|
BLAKE2b-256 checksum How to use checksums |
68b73b524e5213c235591bdbc4c0ea1aa07c0fc33f47d929a17b02e8f793fa92
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|
Release files / sfs_v2-0.0.1.dev1-py3-none-manylinux_2_28_x86_64.whl
| Download URL | sfs_v2-0.0.1.dev1-py3-none-manylinux_2_28_x86_64.whl |
|---|---|
| Size | 5.5 MB |
| Tags | Linux glibc 2.28+ x86-64 Python 3 |
|
SHA-256 checksum How to use checksums |
e720b0a008ee834bfbf6263dee2ff60f02d6f38fabd4f1b1b1ce6507b1d9e05f
|
|
BLAKE2b-256 checksum How to use checksums |
ced37633f0c765f49338309660038ed56aa6a3b87120d4afb47713885baa6f62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.9
|