Voyant API - Python Bindings
Python bindings for Voyant Photonics LiDAR sensors, providing high-performance access to point cloud data.
Installation
pip install voyant-api
Sensor compatibility
| Sensor | Client |
|---|---|
| Carbon | CarbonClient + CarbonConfig |
Meadowlark support ended in v1.0.0. The deprecated
VoyantClienthas been removed — Carbon users useCarbonClient(above). If you still run a Meadowlark sensor, pinvoyant-api < 1.0.0.
Breaking changes in v1.0.0
v1.0.0 moves to a new recording format and reworks the frame API around it. Code
written against 0.x needs the following changes.
points() returns different columns. It was a (N, 7) float32 array of
[x, y, z, radial_vel, snr_linear, nanosecs_since_frame, drop_reason]. It is now a
(N, 12) float64 array with one column per recorded field, in the order they are
stored — beginning [range_m, azimuth_rad, elevation_rad, ...]. Slicing
points()[:, :3] for positions now returns spherical coordinates, not x/y/z, and will
not raise. Either pass cartesian=True to get [x, y, z] in those three slots, or
use xyz(). Index columns by name via VoyantFrame.points_columns() rather than by
position.
Removed frame accessors. spherical(), spherical_v(), points_extended() and
special_test() are gone; every field they exposed is a points() column. xyz(),
xyzv() and their valid_* forms are unchanged. The deprecated voyant_api.utils
shim is also removed — import from voyant_api.pandas_utils / voyant_api.pcd_utils
directly.
Recorder buffer knob removed. VoyantRecorder no longer takes buffer_size_mb —
the write buffer sizes itself. (The C++ bufferSizeMb field and the
voyant_logger_binary --buffer-size-mb flag are gone too.)
Recordings must be converted. The bindings read only the native .vynt format.
VoyantPlayback.open() raises IOError on a pre-v1.0.0 recording, naming the command
that converts it:
voyant_recording_migrate --input drive_01.bin # writes drive_01.vynt alongside the input
The pre-v1.0.0 format stored no sensor state, so converted frames report
carries_state == False and return None from sensor_state() / host_state().
Their points, device identity and timestamps are real.
Pre-v1.0.0 tools cannot read v1.0.0 recordings. Upgrade readers and writers together.
Quick Start
Receiving live data (Carbon)
import time
from voyant_api import CarbonClient, CarbonConfig, init_voyant_logging
init_voyant_logging()
config = CarbonConfig()
config.set_bind_addr("0.0.0.0:5678")
config.set_group_addr("239.255.48.84")
config.set_interface_addr("192.168.1.100")
client = CarbonClient(config)
client.start()
# Press Ctrl+C to stop
while client.is_running():
frame = client.try_receive_frame()
if frame is not None:
print(frame)
# Get point cloud as numpy array (N x 4: x, y, z, doppler_mps)
xyzv = frame.xyzv()
print(f"Points shape: {xyzv.shape}")
else:
time.sleep(0.001)
Config can also be loaded from a JSON file — see CarbonConfig JSON format below.
Recording data
import time
from voyant_api import CarbonClient, CarbonConfig, VoyantRecorder, RecordStatus, init_voyant_logging
init_voyant_logging()
config = CarbonConfig()
config.set_bind_addr("0.0.0.0:5678")
config.set_group_addr("239.255.48.84")
config.set_interface_addr("192.168.1.100")
client = CarbonClient(config)
client.start()
with VoyantRecorder(
output_path="my_recording.vynt",
timestamp_filename=True,
max_total_frames=1000, # Optional: stop after 1000 frames
) as recorder:
while client.is_running():
frame = client.try_receive_frame()
if frame is not None:
status = recorder.record_frame(frame)
if status == RecordStatus.STOP:
break
else:
time.sleep(0.001)
Playing back recordings
from voyant_api import VoyantPlayback, init_voyant_logging
from voyant_api.pandas_utils import frame_to_dataframe
init_voyant_logging()
with VoyantPlayback() as playback:
playback.open("my_recording.vynt")
for frame in playback:
if frame is None:
break
print(frame)
# Convert to pandas DataFrame
df = frame_to_dataframe(frame)
print(df.head())
Editing frames
frame.with_points(matrix) builds a new frame from an edited points() matrix,
keeping everything else — state snapshots, timestamps, frame index, device
identity — from the frame it came from, so the result records exactly like the
original. It works on any frame, live from a CarbonClient or replayed from a
file. The default (spherical) matrix is stored bit-exactly; untouched rows
survive the round trip unchanged.
Editing a recording:
from voyant_api import VoyantFrame, VoyantPlayback, VoyantRecorder, init_voyant_logging
init_voyant_logging()
cols = VoyantFrame.points_columns()
# Invalid returns are dropped as the frames are read, so the output holds only
# valid points. Pass keep_invalid_points=True to carry them through as well.
with VoyantPlayback() as playback, VoyantRecorder(
"edited.vynt", timestamp_filename=False
) as recorder:
playback.open("my_recording.vynt")
for frame in playback:
if frame is None:
break
matrix = frame.points()
matrix = matrix[matrix[:, cols.index("range_m")] <= 50.0] # any numpy edit
recorder.record_frame(frame.with_points(matrix))
The same flow processes a live stream as it records — here keeping only valid,
near points to cut file size. Any edit works, e.g. stamping per-point results
from a live perception pipeline into the user_data column:
# Continues the live-streaming example above (client, time and cols already set up).
with VoyantRecorder("filtered.vynt") as recorder:
while client.is_running():
frame = client.try_receive_frame()
if frame is None:
time.sleep(0.001)
continue
matrix = frame.valid_points()
matrix = matrix[matrix[:, cols.index("range_m")] <= 50.0]
recorder.record_frame(frame.with_points(matrix))
Pass the same cartesian flag you pass to points() — cartesian geometry is
converted back to the stored spherical form (~1e-5 accuracy), and a basis mismatch
cannot be detected: a cartesian=True matrix passed without the flag stores
x, y, z into the range and angle fields. Invalid returns may have no meaningful
x, y, z either — one dropped before a range was measured loses its angles that
way, so edit in the default spherical basis if you are keeping those. A cartesian
row that names no position — all-zero, or carrying NaN/inf — stores as range 0
rather than propagating.
From a pandas DataFrame, select columns by name — column order then can't drift, and a
basis mismatch raises KeyError on the missing geometry columns instead of silently
storing the wrong coordinates:
edited = frame.with_points(df[VoyantFrame.points_columns()].to_numpy())
See py/edit_recording_example.py for a complete script.
Converting recordings to PCD
from voyant_api import VoyantPlayback, init_voyant_logging
from voyant_api.pcd_utils import save_frame_to_pcd, frame_to_pcd
init_voyant_logging()
with VoyantPlayback() as playback:
playback.open("my_recording.vynt")
for frame in playback:
if frame is None:
break
# Save directly to .pcd file
save_frame_to_pcd(frame, f"frame_{frame.frame_index}.pcd")
# Or get a PointCloud object for further processing
pc = frame_to_pcd(frame)
pc.save(f"frame_{frame.frame_index}.pcd")
Sending SDL commands
SDL (Software Defined Lidar) commands configure the sensor at runtime — changing operating state, field of view, frame rate, and waveform parameters.
The recommended Python flow is to start from the latest heartbeat read back,
modify only the fields you want to change, then call send_sdl_blocking().
This preserves the sensor's current SDL settings and, when the sensor is already
streaming point clouds, applies the requested settings while transitioning
through Idle, then resumes PointCloud unless the command requests Idle.
from voyant_api import (
CarbonClient, CarbonConfig,
SdlState, SdlStatus,
init_voyant_logging,
)
init_voyant_logging()
config = CarbonConfig()
config.set_bind_addr("0.0.0.0:5678")
config.set_group_addr("239.255.48.84")
config.set_interface_addr("192.168.1.100")
client = CarbonClient(config)
client.start()
# Wait for the first heartbeat so sensor_state() reflects the live read back.
# See py/sdl_example.py for a complete polling helper.
state = client.sensor_state()
cmd = state.to_sdl_command()
cmd.req_state = SdlState.PointCloud
cmd.hfov_deg = 60.0
cmd.hfov_center_deg = 0.0
cmd.frame_rate_fps = 10.0
# Blocks until the sensor confirms the command or the SDL timeout expires.
status = client.send_sdl_blocking(cmd)
if status == SdlStatus.Applied:
print("Command applied.")
else:
print(f"Command failed: {status}")
API Overview
CarbonClient
Receives live data from Carbon sensors. Construct with a CarbonConfig and call start() before polling for frames.
config = CarbonConfig()
config.set_bind_addr("0.0.0.0:5678")
config.set_group_addr("239.255.48.84")
config.set_interface_addr("192.168.1.100")
config.set_range_max(50.0)
client = CarbonClient(config)
client.start()
CarbonConfig
Configuration for the Carbon pipeline. Construct with defaults and setters, or load from JSON.
# From defaults
config = CarbonConfig()
config.set_bind_addr("0.0.0.0:5678")
# Observer-only: passively receive the point stream without sending anything to the
# sensor (no SDL, time-sync, or comms-health). Use this when another (primary) client
# already owns the sensor, so multiple clients can share one multicast stream. Exactly
# one primary (non-observer) client should be connected.
config.set_observer_only(True)
# Stream transport: how the sensor delivers its push stream. Unicast (the default) makes
# the sensor reply only to this client and arrives reliably even when the host has several
# network connections active at once. Multicast streams to a shared group so several clients
# can view one sensor (use observer-only for the extra ones).
from voyant_api import StreamTransport
config.set_stream_transport(StreamTransport.Multicast)
# From a JSON file
config = CarbonConfig.from_json("config.json")
CarbonConfig JSON format
All fields are optional and fall back to their defaults when omitted. To see all available fields and their current defaults, run:
from voyant_api import CarbonConfig
print(CarbonConfig())
This prints the full nested config with all current defaults, for example:
CarbonConfig { receiver: ReceiverConfig { multicast: MulticastReceiverConfig { bind_addr: "0.0.0.0:5678", group_addr: "239.255.48.84", interface_addr: "192.168.1.100" }, batch_size: 32, ... }, dsp: DspConfig { vel_corr_factor: 1.0, bandwidth_hz: None, elevation_fov_deg: 30.0, ... }, ... }
Any field shown in that output can be set in the JSON file. Fields showing None are unset and use sensor defaults.
SdlCommand
Configures sensor parameters at runtime. For read-modify-write updates, start
from client.sensor_state().to_sdl_command() after the first heartbeat, then
override only the fields you need. All setters validate the value immediately
and raise ValueError if it is out of range.
from voyant_api import SdlState
# Assumes `client` has already been constructed, started, and has received
# its first heartbeat before calling `sensor_state()` / `to_sdl_command()`.
state = client.sensor_state()
cmd = state.to_sdl_command()
cmd.req_state = SdlState.PointCloud # Operating state
cmd.hfov_deg = 60.0 # Horizontal FOV (0.0 – 120.0°)
cmd.hfov_center_deg = 0.0 # FOV center (−60.0 – 60.0°)
cmd.frame_rate_fps = 10.0 # Frame rate (1.0 – 20.0 fps)
cmd.ramp_bandwidth_ghz = 6.0 # Ramp bandwidth (0.5 – 10.0 GHz)
(ramp_length is firmware-fixed at 16.384 µs, so it is read-only — exposed as cmd.ramp_length
for inspection but not settable.)
You can also build a command in one validated call with configure():
cmd = SdlCommand()
cmd.configure(SdlState.PointCloud, 10.0, 60.0, 0.0, 6.0)
# req_state, frame_rate_fps, hfov_deg, hfov_center_deg, ramp_bandwidth_ghz
Static line (linescan). Use the linescan() constructor to park the beam (HFOV 0°). There is
no frame-rate argument — the firmware fixes the line rate at 900 fps. The per-field
hfov_deg/frame_rate_fps setters raise if used to switch between swept and static-line mode; use
linescan()/configure() for that. cmd.is_linescan reports whether a command is a static line.
Note: Linescan beam steering is temporarily unsupported — the sensor centers the mirror regardless — so
hfov_center_degmust be0.0;send_sdlrejects a non-zero center.
cmd = SdlCommand.linescan(SdlState.PointCloud, 6.0)
# req_state, ramp_bandwidth_ghz
In linescan mode cmd.frame_rate_fps reads back the firmware-fixed line rate 900.0 — the wire
field carries a sentinel, not a real fps. A static-line SdlDeviceState reports the same
frame_rate_fps == 900.0 on read-back.
Send with client.send_sdl_blocking(cmd) for the recommended blocking path.
It returns Applied on success or a failure status if any step fails. If the
sensor is currently in PointCloud and the command requests Idle, it sends
the command once and leaves the sensor in Idle. Otherwise, it sends the
requested settings with req_state = Idle, then sends the same settings with
req_state = PointCloud.
For event-loop or real-time callers that cannot block, use client.send_sdl(cmd)
and poll for confirmation with client.poll_sdl().
send_sdl returns a status immediately:
| Status | Meaning |
|---|---|
Pending |
Command sent, awaiting heartbeat confirmation |
InvalidParameter |
A value is out of range — not sent |
BadFovCenterCombo |
FOV/center combination is invalid — not sent |
FovFpsError |
FOV/FPS combination exceeds hardware limits — not sent |
SendFailed |
UDP send failed — check logs |
PreviousCommandPending |
Another command is already in flight — wait for it to resolve |
poll_sdl returns Idle when nothing is in flight, Pending while waiting for confirmation, and a resolved status once the sensor confirms or the command times out:
| Status | Meaning |
|---|---|
Idle |
No command is currently in flight |
Pending |
Waiting for heartbeat confirmation |
Applied |
Sensor confirmed the command was applied |
Timeout |
No heartbeat confirmation within the timeout window |
MaxRetriesExceeded |
Retransmitted the maximum number of times without confirmation |
StreamReset |
Heartbeat frame counter jumped backwards — stream was reset |
| Any rejection status | Sensor rejected the command |
Note: Only one SDL command can be in flight at a time.
Idlemeans nothing is pending and you can send immediately. While a command is in flight,poll_sdlreturnsPending— keep polling until you receive a terminal status before sending another command.
Background-noise calibration
Two blocking operations configure the sensor's background-noise mask. The box is identified from
the sensor's heartbeat — no serial argument needed. Both require the sensor to be in Idle and
leave it in Idle (they do not start streaming):
client.wait_for_heartbeat()— block until the first heartbeat arrives (needed for the box serial). RaisesRuntimeErroron timeout.client.ensure_idle_for_calibration()— drive the sensor toIdlefrom any state (both operations require it). RaisesRuntimeErrorif the transition does not confirm.client.apply_default_background_noise()— write the compiled-in default mask for the connected box. Fast (a few seconds); does not change the sensor's state.client.refine_background_noise(iterations=None)— refine the mask from a covered-window capture. The sensor window must be covered first (the capture assumes background noise only). Cycles the sensor internally and returns it toIdle(~10–20 s).iterationsdefaults when omitted.
# Both operations require a heartbeat (for the box serial) and Idle on entry.
client.wait_for_heartbeat()
client.ensure_idle_for_calibration()
# Apply the built-in default calibration.
client.apply_default_background_noise()
# Or refine it (cover the sensor window first).
client.refine_background_noise()
All four raise RuntimeError if a precondition fails (sensor not Idle, no calibration embedded
for the box, no heartbeat, or the operation itself fails).
While a calibration is running, SDL commands and diagnostic captures on the same client are
rejected (the client drives the sensor itself during refine). Do not run a second client against
the same sensor while calibrating — the two would issue conflicting commands.
Diagnostic capture
For Voyant support: with diagnostic_mode enabled, frames keep invalid points (with drop
reasons), and a diagnostic capture writes the raw peak stream to a .vynt sidecar log while the
point cloud keeps streaming. Record frames alongside it with VoyantRecorder — together the two
files form the support bundle. The client must be running (start() first); the writer runs on
its own thread, so start_diagnostic_capture() returns immediately.
client.start_diagnostic_capture(path, overwrite=False)— begin a capture;pathis used verbatim, so name it after the frame recording it accompanies (e.g.my_recording_peaks.vynt).overwriteallows replacing an existing sidecar file — match the recorder's setting. Runs untilstop_diagnostic_capture(). RaisesRuntimeErrorifdiagnostic_modeis off, the client is not running, or a capture is already in progress.client.stop_diagnostic_capture()— request the active capture to stop. Returns immediately; the file ends on a whole frame.client.is_diagnostic_capturing()—Truewhile a capture is running.client.diagnostic_capture_error()— why the last capture ended badly, orNonefor a capture that completed or is still running — so a caller pollingis_diagnostic_capturing()can tell a finished capture from a broken one.
import time
from voyant_api import CarbonClient, CarbonConfig, VoyantRecorder
config = CarbonConfig()
config.set_diagnostic_mode(True) # before start()
client = CarbonClient(config)
client.start()
with VoyantRecorder("my_recording.vynt", timestamp_filename=False) as recorder:
# Started after the recorder opens, so a refused recording path leaves no
# orphan sidecar running.
client.start_diagnostic_capture("my_recording_peaks.vynt")
frames = 0
while frames < 100:
frame = client.try_receive_frame()
if frame is None:
time.sleep(0.001)
continue
recorder.record_frame(frame)
frames += 1
client.stop_diagnostic_capture()
while client.is_diagnostic_capturing():
time.sleep(0.01)
SensorState
client.sensor_state() returns a snapshot of the latest heartbeat-derived sensor state in physical units.
It is updated on each heartbeat, independently of the frame pipeline — it is not synchronized with any particular frame.
Values are zero/default until the first heartbeat arrives; check state.last_heartbeat_frame > 0 before treating contents as valid.
Note: For state that belongs to a specific frame, use
frame.sensor_state()andframe.host_state()— they return the snapshot recorded with that frame. Useclient.sensor_state()when you want the latest reading regardless of frame.
decode_sensor_state(payload) returns the same SensorState from a stored state
payload — the bytes frame.state_payload() hands back. Use it to read a snapshot that
did not come from a frame you already have, and state_payload() to carry one the
other way.
Typical uses are sensor health monitoring, confirming SDL commands were applied, and logging device identity — not per-frame processing.
state = client.sensor_state()
# Device identity
print(state.device.device_id) # e.g. "CAR-30-005"
print(state.device.fpga_version) # e.g. "v1.2.3"
print(state.device.mcu_version) # e.g. "v1.0.0"
# Current SDL configuration confirmed by sensor
print(state.sdl.device_state) # e.g. SdlState.PointCloud
print(state.sdl.frame_rate_fps) # e.g. 10.0
print(state.sdl.hfov_deg) # e.g. 60.0
# Health / temperatures
print(state.health.fpga_temp_c)
print(state.health.clarity_board_temp_c)
# Frame counters
print(state.counters.total_frame_count)
print(state.counters.total_drops_count)
print(state.counters.any_drops_sticky)
# Timing
print(state.peaks_per_frame)
print(state.last_heartbeat_frame)
TimeSyncState
client.time_sync_state() returns a snapshot of the host↔FPGA clock synchronization health.
The client keeps the FPGA clock aligned to the host in the background (enabled by default); this
reports how well it is tracking. Reads SyncQuality.Unsynced until the first measurement lands.
from voyant_api import SyncQuality
ts = client.time_sync_state()
print(ts.quality) # SyncQuality.{Unsynced, Poor, Fair, Good, Excellent}
print(ts.valid) # True once a fresh measurement exists
print(ts.offset_ns) # host − FPGA clock difference (ns); >0 means the FPGA is behind
print(ts.jitter_ns) # std-dev of the offset over the rolling window (ns)
print(ts.round_trip_ns) # register round-trip of the kept measurement (ns)
print(ts.sample_count) # measurements in the rolling window
print(ts.age_ms) # ms since the last fresh measurement
if ts.quality >= SyncQuality.Good:
print("timestamps are trustworthy")
VoyantRecorder
Records frames to binary files with automatic splitting options.
recorder = VoyantRecorder(
output_path="recording.vynt",
timestamp_filename=True, # Add timestamp to filename
frames_per_file=None, # Split after N frames
duration_per_file=None, # Split after N seconds
size_per_file_mb=None, # Split after N megabytes
max_total_frames=None, # Stop after N total frames
max_total_duration=None, # Stop after N total seconds
max_total_size_mb=None, # Stop after N total megabytes
overwrite=False, # Replace an existing file instead of failing
)
recorder.current_file_path reports the file being written with timestamp and split
naming already applied — the path a caller cannot predict, and the one to build on when
another file has to pair with the recording. It stays readable after finalize().
VoyantPlayback
Plays back recorded data with rate control.
playback = VoyantPlayback(
rate=1.0, # Playback speed (0.0 or None = as fast as possible)
loopback=False, # Loop continuously
keep_invalid_points=False, # True keeps invalid points instead of dropping them
)
playback.open("recording.vynt")
keep_invalid_points=True reveals invalid points during playback (the same flag on
pcd_utils/pandas_utils carries them into converted output). A recording holds them
if it was captured with the client's diagnostic_mode enabled, or if it was written
from frames you constructed or edited yourself; an ordinary recording has none, and
the flag changes nothing for it.
playback.api_version reports the version of the API that wrote the open recording,
including its release status — "1.0.0", "1.0.0-alpha", or None if no file is
open. A converted recording reports the version that produced the original, not the
one that converted it.
Frame data access
frame.points() returns one float64 column per recorded point field, in field
order — VoyantFrame.points_columns() gives the names:
[range_m, azimuth_rad, elevation_rad, doppler_mps, snr, calibrated_reflectance, timestamp_nanosecs, azimuth_idx, elevation_idx, drop_reason, combine_method, user_data]
range_min meters;azimuth_rad/elevation_radin radians, 0 at boresight, positive left and up;doppler_mpspositive moving away;snrlinear (not dB);calibrated_reflectancein dBazimuth_idx/elevation_idx— scan grid position;(0, 0)is the frame's top-left, matching camera image conventionsdrop_reason— numeric code;1means a valid return, any other value means the point was droppedcombine_method— numeric code;0= unknown, non-zero identifies how the point was produceduser_data— the point's two user-owned bytes read as one little-endian u16; opaque to the API
Pass cartesian=True to swap the geometry columns for [x, y, z] (derived; the
default spherical matrix is the exact recorded data).
# NumPy arrays
pts = frame.points() # (N x 12): every recorded point field, float64 (exact)
cart = frame.points(cartesian=True) # (N x 12): geometry columns as x, y, z
xyz = frame.xyz() # (N x 3): [x, y, z], float32, derived from spherical
xyzv = frame.xyzv() # (N x 4): [x, y, z, doppler_mps]
mask = frame.valid_mask() # (N,) bool — e.g. frame.points()[frame.valid_mask()]
edited = frame.with_points(pts) # new frame from an edited matrix; state/metadata carry over
# Each accessor has a valid_* variant restricted to valid returns,
# e.g. frame.valid_points(), frame.valid_xyz().
# Pandas DataFrames (via voyant_api.pandas_utils)
from voyant_api.pandas_utils import frame_to_dataframe
df = frame_to_dataframe(frame) # points_columns() columns; also takes cartesian=
# PCD PointCloud objects (via voyant_api.pcd_utils)
from voyant_api.pcd_utils import frame_to_pcd, save_frame_to_pcd
pc = frame_to_pcd(frame) # default fields: x, y, z + all non-geometry fields
save_frame_to_pcd(frame, "out.pcd")
# Choose your own fields (any set including a full geometry trio,
# x/y/z or range/azimuth/elevation — the rest ride along as attributes):
save_frame_to_pcd(frame, "slim.pcd", fields=["x", "y", "z", "doppler_mps", "snr"])
# Frame metadata
print(frame.frame_index)
print(frame.timestamp) # seconds since the Unix epoch; convenient, ~240 ns resolution
print(frame.timestamp_seconds) # the exact recorded frame-start time...
print(frame.timestamp_nanoseconds) # ...as integers
print(frame.n_points)
print(frame.n_valid_points)
print(frame.device_id)
# Per-frame state snapshots (also available live via client.sensor_state()).
# Both return None for a recording that never stored state — see below.
state = frame.sensor_state() # converted from the raw snapshot on each call
if state is not None:
print(state.device) # DeviceInfo: serial, product, firmware versions
print(state.sdl) # SdlDeviceState: confirmed FOV, fps, state
print(state.health) # HealthState: temperatures, error words
print(state.counters) # CounterState: frame/ramp/drop counts
print(state.calibration) # CalibrationState: doppler, chirp bandwidth, datum
print(state.dsp_header) # DspHeaderState: timestamp, frame start toggle
host = frame.host_state() # what the host knew when it sealed the frame
if host is not None:
print(host.state_age_frames) # snapshot staleness in frames (0 = fresh)
print(host.dropped_ramps) # data-plane ramp drops within this frame
print(host.sync_valid) # time-sync fields hold a fresh measurement
# The same snapshot as the bytes a recording stores, and back again. Also None when
# the frame carries no state.
payload = frame.state_payload()
if payload is not None:
# State objects have no value equality, so compare the fields you care about.
decoded = voyant_api.decode_sensor_state(payload)
assert decoded.device.serial_number == state.device.serial_number
assert decoded.calibration.chirp_bandwidth_hz == state.calibration.chirp_bandwidth_hz
# One-screen summary of the frame and whatever state it has
print(frame.describe())
Recordings without sensor state
The recording format used before v1.0.0 stored no sensor or host state. Those files
must be converted with voyant_recording_migrate before the bindings will read them
(see Breaking changes in v1.0.0), and in the converted
file every frame reports:
frame.carries_state # False
frame.sensor_state() # None
frame.host_state() # None
frame.state_payload() # None
Point data, device identity, timestamps and frame indices are real in those files;
health, calibration, SDL settings and time-sync figures were never recorded. They are
reported as absent rather than as zeros, because zeros convert into plausible-looking
physical values (a zeroed temperature register becomes -273.15 °C) that are easy to
mistake for readings. Guard on carries_state when a script has to handle both:
if frame.carries_state:
print(frame.sensor_state().health.fpga_temp_c)
Re-recording such a frame keeps it marked stateless — at the entry and in the file header — so a converted log can never be mistaken for one captured with state.
VoyantFrame.stateless(matrix, source=..., serial_number=..., timestamp_seconds=..., timestamp_nanoseconds=..., frame_index=...) builds one directly, for points that
reached you without the sensor's heartbeat — a ROS bag, a CSV, any transport that
carried the points alone. The timeline, frame index and device_id record and replay
intact; the frame reports the three fields above as absent, so a reader sees "none was
recorded" instead of defaults that look like readings. Naming a real sensor is allowed
here, unlike synthetic — a frame claiming no measurements may still say where its
points came from — and an out-of-epoch timestamp clamps instead of raising.
Synthetic frames are different: they are state-carrying frames from a software
source, marked by their sim device_id. VoyantFrame.synthetic(matrix, source=..., timestamp_seconds=..., timestamp_nanoseconds=..., frame_index=...) builds a frame
from bare points (the points() layout) — source is the generator's ProductId
(e.g. ProductId.IsaacSim, ProductId.SoftwareSimulator; real sensor ids are
rejected), and the per-frame identity records and replays intact, so a generated
scene — say, a Python-wrapped Isaac Sim run — becomes an analyzable .vynt log.
Chain .with_sdl(cmd) with a configured SdlCommand to declare the configuration
the points were generated under; unauthored state fields hold defaults, not
measurements (a zeroed FPGA temperature reads -273.15 °C). create_test_frame()
frames follow the same model under "SIM-SW". See py/synthetic_scene_example.py
for a complete scene-recording script.
Version introspection
from voyant_api import api_version, interface_contract_version
api_version() # the voyant-api library backing this package, e.g. "1.0.0"
interface_contract_version() # FPGA interface contract it was built for, e.g. "1.5.6"
Both are compiled in, so they report what is actually installed. The interface contract pins the sensor wire protocol, so report the pair in bug reports and in any metadata a downstream system publishes. A sensor's own firmware versions come from a frame instead:
device = frame.sensor_state().device
print(device.fpga_version_major, device.mcu_version_major)
VoyantPlayback.api_version is a different fact again — the version that wrote
an open recording, not the one replaying it.
Features
- High performance: Rust-based implementation, no serialization at the language boundary
- NumPy integration: Direct conversion to NumPy arrays via
frame.points()/frame.xyzv() - Pandas support: DataFrame conversion via
voyant_api.pandas_utils - PCD support: Point Cloud Data export via
voyant_api.pcd_utils - Type hints: Full type annotations for IDE support (
.pyistubs included) - Recording & playback: Save and replay sensor data with timestamp preservation
- Network streaming: Multicast UDP support for live sensor data
- SDL commands: Runtime sensor configuration via
SdlCommand
Complete examples
Full example scripts are available in the voyant-sdk repository:
carbon_client_example.py— Live data streaming with CarbonClientrecorder_example.py— Recording with all optionsplayback_example.py— Playback and processingedit_recording_example.py— Filtering a recording and saving it backpcd_conversion_example.py— Converting recordings to PCD filessdl_example.py— Sending SDL commands (blocking and non-blocking paths)synthetic_scene_example.py— Generating a synthetic scene and recording it to.vyntbackground_noise_calibration_example.py— Applying and refining the noise calibration
System requirements
- Python: 3.9 or later (ARM64/aarch64 Linux wheels currently cover 3.9–3.12)
- Dependencies: NumPy 2.0+, Pandas 2.0+, pypcd4 1.4+
- Platforms: Linux (x86-64 and ARM64/aarch64, including Raspberry Pi and Jetson), Windows (x86-64), macOS (Apple Silicon)
- Firmware: match your sensor's firmware to the API release via the compatibility table in the release notes
Documentation
- Full documentation: https://voyant-photonics.github.io/
- Examples repository: https://github.com/Voyant-Photonics/voyant-sdk
Support
License
Proprietary — for use with Voyant Photonics hardware products only.
Copyright © 2025 Voyant Photonics, Inc. All rights reserved.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file voyant_api-1.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: PyPy, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a93c7b556c893c96b44cb6ff8cb9bb1d91326d870aff06971fd3891a02fef9b5
|
|
| MD5 |
d58ba653f5f1926831f3e5d8b99625d0
|
|
| BLAKE2b-256 |
fc8770ca15757aa129570101adb5675ad41830bdfbd9fe52ef57681c2b064e15
|
File details
Details for the file voyant_api-1.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: PyPy, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c6a3e17af112b38760ce0d6e8e5ea455c5d6a34b311e711ca4cdac689a1b7854
|
|
| MD5 |
c483821adad132ed387cdffbb8bb8b0c
|
|
| BLAKE2b-256 |
d8e0644257718139afcabc14da68d9f2fd4c24cb84d9342d383516d1efca9675
|
File details
Details for the file voyant_api-1.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: PyPy, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0774e64863f27d945af416e2d0819d05e437a5018c631c3be469bcc3547b1b4d
|
|
| MD5 |
8fb376b8126c8c6935c4ba9300c244fc
|
|
| BLAKE2b-256 |
4d5036cfba3c8c2ec08ce9b0329635df165a99d90e2f7f09274c67b51a548a78
|
File details
Details for the file voyant_api-1.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.14t, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f01162e87cb34acbaf9d8bec8fc2716ab279020edfe04976633043979ff116f7
|
|
| MD5 |
7161767db184dd7f79dc977f970775ec
|
|
| BLAKE2b-256 |
c2d6dc1d4c0b5f42ab8dab61b7a72462806954dcaf59c5a4d4db6e89987543f1
|
File details
Details for the file voyant_api-1.0.0-cp314-cp314-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp314-cp314-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.14, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f140d3cf7f3a5b81cb24e794df470c94ab78a8fbac99f91f2e0090c4d49f337
|
|
| MD5 |
10d721d03be174aa64b45fe65dc39482
|
|
| BLAKE2b-256 |
7679db832b7740c6abba943df51faf4939ec8264039cd9309466eb44135edd0c
|
File details
Details for the file voyant_api-1.0.0-cp314-cp314-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp314-cp314-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.14, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0f0f4f0f4378a4a4d25db5c57ff13f511ef18923005524665bce34b0de3c2823
|
|
| MD5 |
9458cc197a3b3c2142a2df703c2a749f
|
|
| BLAKE2b-256 |
221e72193e7d8d1185b91a8baa83b83a343c0467fd9c6a8fe7ff093443066362
|
File details
Details for the file voyant_api-1.0.0-cp314-cp314-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp314-cp314-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.14, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
798a1890f54dbe2ad62439a3bd1fb807ee52f11d6ff4c5c12f4827a85c387025
|
|
| MD5 |
97279fb181877b71d0066d116272a8b8
|
|
| BLAKE2b-256 |
5a2c4222bd09182691acdaf5c5c52b7e1c5e83a4f04d8c457543b817944c6f16
|
File details
Details for the file voyant_api-1.0.0-cp314-cp314-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp314-cp314-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.14, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fd10e5c6a6cebc905c27310fb91ecd9cda23e8ac4501fb3d09527a1059ea2637
|
|
| MD5 |
fcb3ff465dd5350bf3d636ad0662db65
|
|
| BLAKE2b-256 |
3bb2cb0b4155ecc380d1b44e1eb25b10ef007d0e45f94f1c5be22de3ad4249ee
|
File details
Details for the file voyant_api-1.0.0-cp313-cp313-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp313-cp313-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.13, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9167a40e6719486d8afd6e92b7af0c7be453a2f47c10bae57ca211325c17416e
|
|
| MD5 |
ace3068944e91a1e787f3a8041c6d756
|
|
| BLAKE2b-256 |
129162ed1272413198ba865d58dc286a9412be79c69ffc8894c156778565dcf5
|
File details
Details for the file voyant_api-1.0.0-cp313-cp313-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp313-cp313-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.13, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
aec6a27fb18b9f0339d82b0fc60732f98d73c8790ee45c93116d381473c8bb76
|
|
| MD5 |
5fd8d14f17acae21fef93e1930509df8
|
|
| BLAKE2b-256 |
fd71b8dc57c6963fd6f9cf394c48e95a76e85a7bfe6cb202c86bf8a1daa6fe5e
|
File details
Details for the file voyant_api-1.0.0-cp313-cp313-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp313-cp313-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.13, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
dad13ba8efa6a62308ed625cdc60aa4eae4eb73bd432440e29d69dfa97955244
|
|
| MD5 |
b6b4c3a73cd7ddc1c0e45a7e2f60146a
|
|
| BLAKE2b-256 |
81b4b970d757c6523b18ff392c1d0deaa1bba822621ebfb6e4318219d4f21a0f
|
File details
Details for the file voyant_api-1.0.0-cp313-cp313-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp313-cp313-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.13, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
564621a2f280bf96e31aabbd95c3e9b7b274c4a9bf55f845ac13a8ba486d3bb1
|
|
| MD5 |
0d74dc34f2aec2ea7dbe227cfc1ff8e3
|
|
| BLAKE2b-256 |
74e7bef276ff674a9a841baa2f4af6db9ee0b6aaf0d925ff445818eb597a5fce
|
File details
Details for the file voyant_api-1.0.0-cp312-cp312-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp312-cp312-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.12, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a0fc0227d89ff1079f79fbf994d0d77195dbc46acafbd373453d9dbe37b6c7c5
|
|
| MD5 |
a062e3dbd0711ac6c9e9321cec861b22
|
|
| BLAKE2b-256 |
46123fe51f7e49fdd8908e96d7a625b6ced5a1c075ff7fd2fd6e4dd1a79d3511
|
File details
Details for the file voyant_api-1.0.0-cp312-cp312-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp312-cp312-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.12, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ef961508d578eaead602a1595c720b4a58f40288d63e4f1470922881adb370de
|
|
| MD5 |
3ffd7ce87c2007f9f690bd76ea195196
|
|
| BLAKE2b-256 |
c4359cf519bb4825af662a3f076be60e792ed88fb44d969bde99c148600d1f71
|
File details
Details for the file voyant_api-1.0.0-cp312-cp312-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp312-cp312-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.12, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a8584da60e6c29ff4a3ea1b742750446da748cd19afbe2e8238fe8cfd0b175ee
|
|
| MD5 |
146c886892f2e6ca1b0af0bdb29790a2
|
|
| BLAKE2b-256 |
23d7d5b2e94f2eb9ca2ac5bc55e1d139b2b8f1d279ff6195a6513f0088df95c5
|
File details
Details for the file voyant_api-1.0.0-cp312-cp312-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp312-cp312-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.12, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
150580671e7e43831b4d352d13eb8873a39f5c31db848083344bb41646a44f06
|
|
| MD5 |
e56e93fb738c4a6c3d56bb00c552c917
|
|
| BLAKE2b-256 |
1a9bcebb783d4585fde9e4362332731ce3172843de49bb4e5447f53a3e23f906
|
File details
Details for the file voyant_api-1.0.0-cp311-cp311-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp311-cp311-win_amd64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.11, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ce652a7bc37bc4124d209e90421cdfe04eed6b6a46f021cf02ba4084f11006be
|
|
| MD5 |
5dbf578cb1b0c92dfb1fac105a7719b4
|
|
| BLAKE2b-256 |
3e7b2d096c16e58b858f2b5a30391ca74e931732cbf6a485cd4d1d5b73290a51
|
File details
Details for the file voyant_api-1.0.0-cp311-cp311-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp311-cp311-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.11, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
a269cede22ffeaf7f8a51ce1e818025f40789cfe9664154621c797ea5fc2c817
|
|
| MD5 |
565600af8b722f677263e28cf2a55598
|
|
| BLAKE2b-256 |
b5660e186bf4dc7a3cc4670c447087b664f94294c83729cbcb9549015e3054ad
|
File details
Details for the file voyant_api-1.0.0-cp311-cp311-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp311-cp311-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.11, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
672948b30daf08ed658729597aa136691f6185caf056fc1df8970914974edd63
|
|
| MD5 |
dbf8c3e76c1ee99393be73ac7bac0bd6
|
|
| BLAKE2b-256 |
6799f7df00a574198deb7265cb3c7a5a381d39c9537221d3203b5a6b59f6213b
|
File details
Details for the file voyant_api-1.0.0-cp311-cp311-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp311-cp311-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.11, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
02df4df180641079a8000240665e47227c084b885a961734abe61de42fc02caa
|
|
| MD5 |
c13cdac15878d945f64d3ef5cae08efa
|
|
| BLAKE2b-256 |
0ab9a20b65613d334e5a1e5ff822166da0b55f615f2514103440c79c82e387cf
|
File details
Details for the file voyant_api-1.0.0-cp310-cp310-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp310-cp310-win_amd64.whl
- Upload date:
- Size: 1.8 MB
- Tags: CPython 3.10, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e945a91b9d67fa1826b4f5872f73c388b69e4566bfaef551a0d19a1f1436804f
|
|
| MD5 |
c2e52d6634b3bb75fd862d1ffe7af1da
|
|
| BLAKE2b-256 |
bc346a306c7d03b495548c9539ee57019d4000085fb91d01e7df65b851e79da5
|
File details
Details for the file voyant_api-1.0.0-cp310-cp310-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp310-cp310-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.10, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
01d299307335dc59d932109733b1562227dbddc894f8773a53b92a231b2eb308
|
|
| MD5 |
f322fe78ff992b92ac6ea0edd0ad4917
|
|
| BLAKE2b-256 |
edfc7a10c51b1ac13d931df16a0a21b276b81eab163319a0dc822266ca664f25
|
File details
Details for the file voyant_api-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp310-cp310-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.10, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f25a251b233b71ac44e031c0ad1bf9f899a5e9cd744d530f4f4b4e15148112ba
|
|
| MD5 |
c892ef2e49c1ec7d63e99fb2aa5b3157
|
|
| BLAKE2b-256 |
1a6afbd733a49a3b25e6cd969f7c831cf8287cdd6c1736464b4d91a2115f78bf
|
File details
Details for the file voyant_api-1.0.0-cp310-cp310-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp310-cp310-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.10, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c8ed11a7fd4446dd517318fea9a9c75b644b42190cc80fd187d86553f9a104e9
|
|
| MD5 |
af1da4321c84fccce669d27830337618
|
|
| BLAKE2b-256 |
588fcc846b7c60d20f4200570995a875ea6e44c46a8bc3c737b3510693c96f7f
|
File details
Details for the file voyant_api-1.0.0-cp39-cp39-win_amd64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp39-cp39-win_amd64.whl
- Upload date:
- Size: 1.9 MB
- Tags: CPython 3.9, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5e0951c668e86b2a3ad6b9c3feeb7c220bf78207990f8229fe4585ce3c83f9ae
|
|
| MD5 |
cfa9e2491ce36e3beb71a38c5fd90c8f
|
|
| BLAKE2b-256 |
2242a1a155197b42a4e8f67fc6daf6f918b190d90da5ad30b5abf46271c0d1b7
|
File details
Details for the file voyant_api-1.0.0-cp39-cp39-manylinux_2_34_x86_64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp39-cp39-manylinux_2_34_x86_64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.9, manylinux: glibc 2.34+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
098c6fadab494e9f94c6bc31fd9ea08aad9ecb116f7ecac64a45d8311b993523
|
|
| MD5 |
50851be557c4ed355938ea74931eea47
|
|
| BLAKE2b-256 |
a4366fa0ab188b55c5aa57081bfee5b149edad3c8f5810e78951f1b079f16a33
|
File details
Details for the file voyant_api-1.0.0-cp39-cp39-manylinux_2_28_aarch64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp39-cp39-manylinux_2_28_aarch64.whl
- Upload date:
- Size: 2.2 MB
- Tags: CPython 3.9, manylinux: glibc 2.28+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
39e480a044e8b1d806f771587b6a25d42b9fe4d86ccf752e20d69ed2b6f21fd4
|
|
| MD5 |
9f673ee7c2d15f81fd408edc05f9618e
|
|
| BLAKE2b-256 |
48b87a46624d199b605fd1a5d82a8319a8182de64fb47750232a70e79b055b85
|
File details
Details for the file voyant_api-1.0.0-cp39-cp39-macosx_11_0_arm64.whl.
File metadata
- Download URL: voyant_api-1.0.0-cp39-cp39-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.0 MB
- Tags: CPython 3.9, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2efad465d2e22e79118e31b4020d0a4f647227a4237db2bf23ca53148dcc7394
|
|
| MD5 |
e0deb897fe1b59d21f93aa7335dc4082
|
|
| BLAKE2b-256 |
dad2824d15e0741215934c70c47da4577afc823f039611eba4c29f3cfb29b111
|