-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpyproject.toml
More file actions
129 lines (120 loc) · 4.88 KB
/
Copy pathpyproject.toml
File metadata and controls
129 lines (120 loc) · 4.88 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "syncfield"
version = "0.8.14"
description = "Multi-modal capture orchestration framework with precision sync for Physical AI data collection"
readme = "README.md"
license = "Apache-2.0"
requires-python = ">=3.12"
authors = [{ name = "OpenGraph Labs" }]
keywords = ["synchronization", "timestamp", "multi-camera", "robotics", "data-collection", "physical-ai"]
classifiers = [
"Development Status :: 3 - Alpha",
"Intended Audience :: Developers",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.13",
"Topic :: Scientific/Engineering",
]
# Default install ships the canonical first-run stack: a UVC webcam adapter,
# the browser viewer, and the sounddevice-backed chirp / countdown player
# (so the 3/2/1 ticks and start/stop chirps are audible out of the box).
# Heavier / platform-specific adapters (BLE, OAK, OVISION, off-host cameras,
# multi-host control plane) stay opt-in via the optional-dependencies
# block below.
dependencies = [
"av>=12.0.0",
"numpy>=1.21",
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"Pillow>=10.0.0",
"sounddevice>=0.4.6",
]
[project.optional-dependencies]
ble = ["bleak>=0.21", "pyserial>=3.5"] # pyserial: OGLO USB CDC wired transport
# OakCameraStream supports both DepthAI major lines and picks the pipeline
# path from the installed version: depthai 2.x uses the legacy API with
# DIRECT mono GRAY8 encoding (full native mono resolution, no ImageManip
# ceiling — preferred on RVC2 boards), depthai 3.x uses the v3 API (required
# for RVC4). PyAV writes the MP4s (also via _video_encoder, hence numpy).
# Install `syncfield[oak]` for the full OAK capture path.
oak = ["depthai>=2.30", "av>=12.0.0", "numpy>=1.21"]
# OVISION per-unit flash calibration is a Kalibr YAML payload read through
# the Linux UVC Extension Unit. Video/metadata parsing remains dependency-free.
ovision = ["PyYAML>=6.0"]
# mDNS-based multi-host session rendezvous (syncfield.multihost). Required
# only when you want a leader/follower session discovered automatically
# on the local network — single-host sessions do not need this.
multihost = [
"zeroconf>=0.130",
"fastapi>=0.104.0",
"uvicorn[standard]>=0.24.0",
"httpx>=0.25.0",
]
# Camera adapters that talk to off-host cameras:
# * Insta360 Go3S — BLE trigger via bleak + WiFi/OSC HTTP via aiohttp.
# * MetaQuestCameraStream — stereo passthrough over HTTP via httpx to
# the SyncField Quest Sender companion app; pulls the on-device
# recorded MP4 + timestamps JSONL after stop_recording().
camera = [
"bleak>=0.21",
"aiohttp>=3.9",
"httpx>=0.25.0",
"zeroconf>=0.130",
]
all = [
"bleak>=0.21",
"aiohttp>=3.9",
"depthai>=3.0.0",
"zeroconf>=0.130",
"httpx>=0.25.0",
"PyYAML>=6.0",
]
[project.urls]
Homepage = "https://opengraphlabs.com/"
Repository = "https://github.com/OpenGraphLabs/syncfield-python"
Documentation = "https://github.com/OpenGraphLabs/syncfield-python#readme"
Issues = "https://github.com/OpenGraphLabs/syncfield-python/issues"
[tool.hatch.build.targets.wheel]
packages = ["src/syncfield"]
# viewer/frontend/ is the React/TypeScript build *input* (vite + .tsx +
# package.json + node_modules). The runtime only reads viewer/static/
# (the prebuilt SPA bundle), which is force-included below. Excluding
# the source tree keeps the wheel small and avoids shipping our
# frontend sources through PyPI.
exclude = [
"src/syncfield/viewer/frontend",
]
[tool.hatch.build.targets.wheel.force-include]
"src/syncfield/viewer/static" = "syncfield/viewer/static"
[tool.hatch.build.targets.sdist.force-include]
"src/syncfield/viewer/static" = "src/syncfield/viewer/static"
[tool.pytest.ini_options]
testpaths = ["tests"]
pythonpath = ["src"]
asyncio_mode = "auto"
# The suite is dominated by wall-clock waits (reconnect backoffs, health
# timers, mDNS fallbacks), not CPU: serially it runs ~50 minutes, under xdist
# it completes in ~40 seconds with an identical failure set (measured
# 2026-08-01, 1247 passed). Parallel is therefore the default everywhere —
# use `-p no:xdist` only when debugging a single test interactively.
# The per-test timeout converts any hung network/IO test into a visible
# failure instead of a stuck CI job.
addopts = ["-n", "auto"]
timeout = 120
markers = [
"hardware: tests that require physical hardware (cameras, BLE devices)",
"slow: integration tests that touch real IO (mDNS sockets, filesystem, etc.)",
"real_multihost: opt out of the unit-conftest patch that no-ops SessionOrchestrator._bring_multihost_online — use when the test needs the real control plane / advertiser / browser",
]
[dependency-groups]
dev = [
"pytest>=8.4.2",
"pytest-aiohttp>=1.1.0",
"pytest-asyncio>=1.2.0",
"pytest-mock>=3.12.0",
"pytest-timeout>=2.4.0",
"pytest-xdist>=3.6.0",
]