python-aidot-cameras 0.7.21__tar.gz → 0.7.22__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {python_aidot_cameras-0.7.21/src/python_aidot_cameras.egg-info → python_aidot_cameras-0.7.22}/PKG-INFO +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/pyproject.toml +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/client.py +73 -28
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22/src/python_aidot_cameras.egg-info}/PKG-INFO +1 -1
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/python_aidot_cameras.egg-info/SOURCES.txt +1 -0
- python_aidot_cameras-0.7.22/tests/test_sdes_fast_liveplay.py +70 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/LICENSE +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/MANIFEST.in +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/README.md +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/setup.cfg +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/aes_utils.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/constants.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/controls.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/go2rtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/lan_control.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/models.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/playback.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/protocol.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/sdes.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/tutk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/camera/webrtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/client.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/const.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/credentials.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/device_client.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/discover.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/exceptions.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/g711.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/login_const.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/__init__.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/device_client_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/device_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/discover_model.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/py.typed +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/python_aidot_cameras.egg-info/dependency_links.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/python_aidot_cameras.egg-info/requires.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/python_aidot_cameras.egg-info/top_level.txt +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_alarm_event.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_backoff.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_go2rtc.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_highport_nomination.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_lan_control.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_live_stream_param.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_motion_poll.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_no_undefined_names.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_post_merge_hardening.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_sdes_idle_release.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_sdes_sprop.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_sdes_talk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_sdes_watchdog.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_serve_relay.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_speak.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_stream_cap.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_stream_idle.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_talk.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_terminal_ack.py +0 -0
- {python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_token_refresh.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.22
|
|
4
4
|
Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
|
|
5
5
|
Author-email: cbrightly <chris.brightly@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "python-aidot-cameras"
|
|
7
|
-
version = "0.7.
|
|
7
|
+
version = "0.7.22"
|
|
8
8
|
description = "Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -2531,6 +2531,18 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
2531
2531
|
except (TypeError, ValueError):
|
|
2532
2532
|
return 120.0
|
|
2533
2533
|
|
|
2534
|
+
def _resolve_sdes_fast_liveplay(self) -> bool:
|
|
2535
|
+
"""Whether to skip the ~2 s livePlayResp wait for SDES (P5, EXPERIMENTAL).
|
|
2536
|
+
|
|
2537
|
+
Per-camera ``sdes_fast_liveplay`` (set via start_keepalive) wins; else the
|
|
2538
|
+
``AIDOT_SDES_FAST_LIVEPLAY`` env (truthy = 1/true/yes/on), default off.
|
|
2539
|
+
Only consulted for SDES cameras (the caller gates on is_sdes_camera)."""
|
|
2540
|
+
opt = getattr(self, "_sdes_fast_liveplay_opt", None)
|
|
2541
|
+
if opt is not None:
|
|
2542
|
+
return bool(opt)
|
|
2543
|
+
return os.environ.get("AIDOT_SDES_FAST_LIVEPLAY", "").strip().lower() in (
|
|
2544
|
+
"1", "true", "yes", "on")
|
|
2545
|
+
|
|
2534
2546
|
def _maybe_start_serve_relay(self, serve_url: Optional[str]) -> "Optional[_ServeRelay]":
|
|
2535
2547
|
"""Hold the public serve port via a _ServeRelay so an eager go2rtc pull
|
|
2536
2548
|
connects-and-waits instead of hitting ECONNREFUSED during the ~16-25s
|
|
@@ -3347,16 +3359,9 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
3347
3359
|
# the livePlayResp ack, which is purely a camera accept/reject we don't
|
|
3348
3360
|
# need to block on (the official app never waits for it). So this targeted
|
|
3349
3361
|
# skip is expected to be SCTP-safe and shave ~2 s off the SDES cold start.
|
|
3350
|
-
# Off by default, pending live
|
|
3362
|
+
# Off by default, pending live validation. Applied in _open_sdes_stream
|
|
3363
|
+
# (the SDES path has its own livePlayResp wait); start_keepalive(
|
|
3351
3364
|
# sdes_fast_liveplay=...) wins, else AIDOT_SDES_FAST_LIVEPLAY env.
|
|
3352
|
-
_sdes_skip_lp = False
|
|
3353
|
-
if self.is_sdes_camera:
|
|
3354
|
-
_sl = getattr(self, "_sdes_fast_liveplay_opt", None)
|
|
3355
|
-
if _sl is None:
|
|
3356
|
-
_sl = os.environ.get(
|
|
3357
|
-
"AIDOT_SDES_FAST_LIVEPLAY", "").strip().lower() in (
|
|
3358
|
-
"1", "true", "yes", "on")
|
|
3359
|
-
_sdes_skip_lp = bool(_sl)
|
|
3360
3365
|
|
|
3361
3366
|
# Wake battery cameras via the cloud HTTP low-power endpoint before the
|
|
3362
3367
|
# handshake (matches the app, which fires the HTTP wake so a sleeping camera
|
|
@@ -4145,20 +4150,24 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4145
4150
|
# SDP/ICE immediately - losing fast-fail on rejection (rare; ICE then
|
|
4146
4151
|
# fails instead) in exchange for ~2 s off every LAN connect.
|
|
4147
4152
|
if _fast_connect:
|
|
4153
|
+
_LOGGER.info(
|
|
4154
|
+
"signaling-wait[%s] livePlayResp skipped (fast_connect)",
|
|
4155
|
+
self.device_id)
|
|
4148
4156
|
_status(
|
|
4149
4157
|
"AIDOT_FAST_CONNECT: skipping livePlayResp wait (~2s) -"
|
|
4150
4158
|
" proceeding to SDP/ICE (app-parity, no fast-fail on reject)"
|
|
4151
4159
|
)
|
|
4152
|
-
elif _sdes_skip_lp:
|
|
4153
|
-
_status(
|
|
4154
|
-
"AIDOT_SDES_FAST_LIVEPLAY: skipping livePlayResp wait (~2s)"
|
|
4155
|
-
" for SDES - full ICE/TURN/SCTP handshake retained (experiment)"
|
|
4156
|
-
)
|
|
4157
4160
|
else:
|
|
4161
|
+
# Instrumented: how long this wait actually costs (it returns as
|
|
4162
|
+
# soon as livePlayResp arrives; the 2s is only paid on timeout).
|
|
4163
|
+
# This is exactly the cost the sdes_fast_liveplay experiment skips.
|
|
4164
|
+
_lp_t0 = time.monotonic()
|
|
4165
|
+
_lp_arrived = False
|
|
4158
4166
|
try:
|
|
4159
4167
|
_lp_resp = await asyncio.wait_for(
|
|
4160
4168
|
asyncio.shield(liveplay_resp_fut), timeout=2.0
|
|
4161
4169
|
)
|
|
4170
|
+
_lp_arrived = True
|
|
4162
4171
|
_lp_code = int(_lp_resp.get("code", 200))
|
|
4163
4172
|
_lp_on = int(_lp_resp.get("livePlay", 1))
|
|
4164
4173
|
if _lp_code not in (0, 200) or _lp_on == 0:
|
|
@@ -4167,6 +4176,10 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4167
4176
|
)
|
|
4168
4177
|
except TimeoutError:
|
|
4169
4178
|
pass
|
|
4179
|
+
_LOGGER.info(
|
|
4180
|
+
"signaling-wait[%s] livePlayResp elapsed=%dms arrived=%s",
|
|
4181
|
+
self.device_id,
|
|
4182
|
+
int((time.monotonic() - _lp_t0) * 1000), _lp_arrived)
|
|
4170
4183
|
# Short extra wait for getIceConfigResp - the server may only respond
|
|
4171
4184
|
# once a live camera session is active (i.e. after livePlayReq).
|
|
4172
4185
|
# Waiting here ensures TURN credentials arrive before RTCPeerConnection
|
|
@@ -4178,11 +4191,18 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
4178
4191
|
# per-session TURN relay credentials, which LAN-direct doesn't need;
|
|
4179
4192
|
# remote/strict-NAT cameras do, hence this is opt-in (see flag above).
|
|
4180
4193
|
if not ice_config_fut.done() and not _fast_connect:
|
|
4194
|
+
_ic_t0 = time.monotonic()
|
|
4195
|
+
_ic_arrived = False
|
|
4181
4196
|
try:
|
|
4182
4197
|
await asyncio.wait_for(asyncio.shield(ice_config_fut), timeout=3.0)
|
|
4198
|
+
_ic_arrived = True
|
|
4183
4199
|
_status("getIceConfigResp received (post-livePlayReq)")
|
|
4184
4200
|
except TimeoutError:
|
|
4185
4201
|
pass # proceed without TURN; synthetic candidates are fallback
|
|
4202
|
+
_LOGGER.info(
|
|
4203
|
+
"signaling-wait[%s] getIceConfigResp elapsed=%dms arrived=%s",
|
|
4204
|
+
self.device_id,
|
|
4205
|
+
int((time.monotonic() - _ic_t0) * 1000), _ic_arrived)
|
|
4186
4206
|
elif _fast_connect:
|
|
4187
4207
|
_status(
|
|
4188
4208
|
"AIDOT_FAST_CONNECT: skipping getIceConfigResp wait"
|
|
@@ -7027,24 +7047,49 @@ class CameraMixin(_CameraControlsMixin):
|
|
|
7027
7047
|
# webrtcReq. The echo confirms the MQTT pipeline to this device is live
|
|
7028
7048
|
# and the broker session is registered. Fall through after 5 s if it
|
|
7029
7049
|
# never arrives (same safety as the old fixed 0.5 s sleep, but adaptive).
|
|
7050
|
+
# P5 (experimental, opt-in via sdes_fast_liveplay): instrumentation showed
|
|
7051
|
+
# the echo and livePlayResp waits BOTH always time out for the SDES cameras
|
|
7052
|
+
# measured (echo/resp never arrive) yet streaming succeeds - i.e. ~6 s of
|
|
7053
|
+
# dead padding. When the flag is on, cap the echo wait short and skip the
|
|
7054
|
+
# livePlayResp wait; the full ICE/TURN/SCTP handshake is untouched. This
|
|
7055
|
+
# is the SDES path's OWN livePlay waits (the DTLS gate above never runs for
|
|
7056
|
+
# SDES: use_sdes is True there).
|
|
7057
|
+
_skip_lp = self._resolve_sdes_fast_liveplay()
|
|
7058
|
+
_echo_timeout = 1.5 if _skip_lp else 5.0
|
|
7059
|
+
_echo_t0 = time.monotonic()
|
|
7030
7060
|
try:
|
|
7031
|
-
await _asyncio.wait_for(liveplay_echo_ev.wait(), timeout=
|
|
7061
|
+
await _asyncio.wait_for(liveplay_echo_ev.wait(), timeout=_echo_timeout)
|
|
7032
7062
|
_status("livePlayReq echo received - sending webrtcReq, ICE, then launching ffmpeg")
|
|
7033
7063
|
except TimeoutError:
|
|
7034
|
-
_status("no livePlayReq echo in
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7038
|
-
|
|
7039
|
-
|
|
7040
|
-
|
|
7041
|
-
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7064
|
+
_status(f"no livePlayReq echo in {_echo_timeout:.1f}s - sending webrtcReq,"
|
|
7065
|
+
" ICE, then launching ffmpeg anyway")
|
|
7066
|
+
_LOGGER.info(
|
|
7067
|
+
"signaling-wait[%s] livePlayReq-echo elapsed=%dms (timeout=%.1fs)",
|
|
7068
|
+
self.device_id, int((time.monotonic() - _echo_t0) * 1000), _echo_timeout)
|
|
7069
|
+
# livePlayResp: explicit camera accept/reject before SDP/ICE.
|
|
7070
|
+
if _skip_lp:
|
|
7071
|
+
_LOGGER.info(
|
|
7072
|
+
"signaling-wait[%s] livePlayResp skipped (sdes_fast_liveplay)",
|
|
7073
|
+
self.device_id)
|
|
7074
|
+
else:
|
|
7075
|
+
_lp_t0 = time.monotonic()
|
|
7076
|
+
_lp_arrived = False
|
|
7077
|
+
try:
|
|
7078
|
+
_lp_resp_sdes = await _asyncio.wait_for(
|
|
7079
|
+
_asyncio.shield(liveplay_resp_fut), timeout=1.0
|
|
7045
7080
|
)
|
|
7046
|
-
|
|
7047
|
-
|
|
7081
|
+
_lp_arrived = True
|
|
7082
|
+
_lp_code_sdes = int(_lp_resp_sdes.get("code", 200))
|
|
7083
|
+
_lp_on_sdes = int(_lp_resp_sdes.get("livePlay", 1))
|
|
7084
|
+
if _lp_code_sdes not in (0, 200) or _lp_on_sdes == 0:
|
|
7085
|
+
raise RuntimeError(
|
|
7086
|
+
f"livePlay rejected by camera (code={_lp_code_sdes}, livePlay={_lp_on_sdes})"
|
|
7087
|
+
)
|
|
7088
|
+
except TimeoutError:
|
|
7089
|
+
pass
|
|
7090
|
+
_LOGGER.info(
|
|
7091
|
+
"signaling-wait[%s] livePlayResp elapsed=%dms arrived=%s",
|
|
7092
|
+
self.device_id, int((time.monotonic() - _lp_t0) * 1000), _lp_arrived)
|
|
7048
7093
|
|
|
7049
7094
|
# --- Build local-receiver SDP for ffmpeg ----------------------------- #
|
|
7050
7095
|
# Built BEFORE sending webrtcReq so ffmpeg is already listening on the
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python-aidot-cameras
|
|
3
|
-
Version: 0.7.
|
|
3
|
+
Version: 0.7.22
|
|
4
4
|
Summary: Control AiDot/Leedarson WiFi lights and cameras (WebRTC streaming, two-way audio, PTZ, controls)
|
|
5
5
|
Author-email: cbrightly <chris.brightly@gmail.com>
|
|
6
6
|
License-Expression: MIT
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""Unit tests for _resolve_sdes_fast_liveplay - the P5 flag (EXPERIMENTAL).
|
|
2
|
+
|
|
3
|
+
P5 skips only the ~2s livePlayResp wait for SDES cameras. This locks the
|
|
4
|
+
opt/env precedence (per-camera kwarg wins over AIDOT_SDES_FAST_LIVEPLAY env,
|
|
5
|
+
default off) so the wiring is verifiable without a camera. The actual stability
|
|
6
|
+
effect is validated by real-world soak (see scripts/sdes_soak_monitor.py), not
|
|
7
|
+
here.
|
|
8
|
+
"""
|
|
9
|
+
import os
|
|
10
|
+
import sys
|
|
11
|
+
|
|
12
|
+
sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "src"))
|
|
13
|
+
|
|
14
|
+
import aidot.camera.client as cc
|
|
15
|
+
|
|
16
|
+
_CAM = next(v for v in vars(cc).values()
|
|
17
|
+
if isinstance(v, type) and "_resolve_sdes_fast_liveplay" in v.__dict__)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def _cam():
|
|
21
|
+
return _CAM.__new__(_CAM)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_default_off(monkeypatch):
|
|
25
|
+
monkeypatch.delenv("AIDOT_SDES_FAST_LIVEPLAY", raising=False)
|
|
26
|
+
assert _cam()._resolve_sdes_fast_liveplay() is False
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_env_truthy_values(monkeypatch):
|
|
30
|
+
for val in ("1", "true", "TRUE", "yes", "on", " On "):
|
|
31
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", val)
|
|
32
|
+
assert _cam()._resolve_sdes_fast_liveplay() is True, val
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def test_env_falsey_values(monkeypatch):
|
|
36
|
+
for val in ("0", "false", "no", "off", ""):
|
|
37
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", val)
|
|
38
|
+
assert _cam()._resolve_sdes_fast_liveplay() is False, val
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def test_kwarg_option_wins_over_env(monkeypatch):
|
|
42
|
+
monkeypatch.setenv("AIDOT_SDES_FAST_LIVEPLAY", "1")
|
|
43
|
+
cam = _cam()
|
|
44
|
+
cam._sdes_fast_liveplay_opt = False # start_keepalive(sdes_fast_liveplay=False)
|
|
45
|
+
assert cam._resolve_sdes_fast_liveplay() is False
|
|
46
|
+
|
|
47
|
+
cam2 = _cam()
|
|
48
|
+
monkeypatch.delenv("AIDOT_SDES_FAST_LIVEPLAY", raising=False)
|
|
49
|
+
cam2._sdes_fast_liveplay_opt = True
|
|
50
|
+
assert cam2._resolve_sdes_fast_liveplay() is True
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
if __name__ == "__main__":
|
|
54
|
+
import traceback
|
|
55
|
+
|
|
56
|
+
class _MP:
|
|
57
|
+
def setenv(self, k, v): os.environ[k] = v
|
|
58
|
+
def delenv(self, k, raising=False): os.environ.pop(k, None)
|
|
59
|
+
|
|
60
|
+
_fail = 0
|
|
61
|
+
for _k, _v in sorted(globals().items()):
|
|
62
|
+
if _k.startswith("test_"):
|
|
63
|
+
try:
|
|
64
|
+
_v(_MP()) if _v.__code__.co_argcount else _v()
|
|
65
|
+
print(f"PASS {_k}")
|
|
66
|
+
except Exception:
|
|
67
|
+
_fail += 1
|
|
68
|
+
print(f"FAIL {_k}")
|
|
69
|
+
traceback.print_exc()
|
|
70
|
+
raise SystemExit(1 if _fail else 0)
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/device_client_model.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/device_model.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/src/aidot/models/discover_model.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_highport_nomination.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_no_undefined_names.py
RENAMED
|
File without changes
|
{python_aidot_cameras-0.7.21 → python_aidot_cameras-0.7.22}/tests/test_post_merge_hardening.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|