fix(python-sdk): pass CommandFactory (not invoked coroutine) to observables - #918
fix(python-sdk): pass CommandFactory (not invoked coroutine) to observables#918akeildev wants to merge 1 commit into
Conversation
…vables
`GoproObserverDistinctInitial.start()` calls `self._register_command_factory()`,
and the type is `CommandFactory = Callable[[], Coroutine[...]]` — i.e. a factory
that *returns* a coroutine. Several call sites instead passed an already-invoked
coroutine, so `start()` tried to call a coroutine object:
TypeError: 'coroutine' object is not callable
This breaks `AccessPointFeature.connect()` (and therefore COHN provisioning,
which depends on it) deterministically, as well as `LiveStreamController`'s
status observable.
Fix the call sites to pass factories, matching the correct pattern already used
elsewhere (e.g. cohn_feature.py, api/builders.py):
- access_point_feature.py: wrap `scan_wifi_networks()` in a lambda; build the
wifi-connect command with functools.partial.
- livestream.py: wrap register/unregister status commands in lambdas.
Tested against a HERO12 Black: `access_point.connect()` now completes the wifi
scan and returns a normal Result instead of raising.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_017S8amPPZwqFt7hqdNk3yJh
|
Independent reproduction on a MAX 2 (firmware I hit this while writing a LAN media-sync tool and arrived at the same fix before finding this PR, so this is a second data point on different hardware from the HERO12 in the description. Impact is broader than "wifi scanning fails": it blocks COHN provisioning outright, since With the fix applied, provisioning completes normally against an already-saved network: and the camera is then reachable over HTTPS with the issued certificate ( On completeness — the three call sites here appear to be the full set. Grepping every observable registration in the SDK after applying this patch: which is the One small thing that may be worth folding in: |
Description
GoproObserverDistinctInitial.start()invokes the registration command as a factory:Several call sites pass an already-invoked coroutine instead of a factory, so
start()ends up calling a coroutine object:This makes
AccessPointFeature.connect()fail deterministically, which in turn breaks COHN provisioning (it callsaccess_point.connect()), and also affectsLiveStreamController's status observable.Affected call sites (passing
coro()where aCallable[[], coro]is expected)features/access_point_feature.py:61—register_command=self._gopro.ble_command.scan_wifi_networks()features/access_point_feature.py:104—register_command=command(wherecommandis an invoked coroutine)features/streaming/livestream.py:82,85—register_command/unregister_commandThe correct pattern (a
lambda:factory) is already used elsewhere, e.g.features/cohn_feature.py:69andapi/builders.py.Fix
Wrap these in factories:
scan_wifi_networks()→lambda: ...scan_wifi_networks()functools.partial(...)lambda: ...No behavior change beyond deferring coroutine creation to call time, as the type contract intends.
Testing
Verified against a HERO12 Black. Before:
gopro.access_point.connect(ssid, pw)raised'coroutine' object is not callable. After: it completes the WiFi scan and returns a normalResult(e.g. a clean<Failure: Could not find SSID: ...>for a non-existent SSID, and provisioning proceeds for a real one).py_compilepasses on both files.Related
May explain user-reported COHN provisioning /
scan_wifi_networksfailures discussed in #744.Checklist
🤖 Generated with Claude Code
https://claude.ai/code/session_017S8amPPZwqFt7hqdNk3yJh