-
Notifications
You must be signed in to change notification settings - Fork 0
Client
Here is a notebook demonstrating the fundamentals of the GatewayClient
object.
This class is a convenience wrapper around the various HTTP
requests used to interact with a running GatewayServer
(with REST
endpoints enabled). It relies on the httpx and aiohttp libraries, and derives most of its functionality from the openapi specification provided on the running GatewayServer
(usually available at /openapi.json
).
A GatewayClient
is configured via a GatewayClientConfig
, a minimal pydantic model to specify details such as protocol (http
/https
), host, port, etc. By default, we should provide host
and port
.
We can also specify in the config return_raw_json
, which specifies whether we would like to return the raw json response, or a ResponseWrapper
object for REST
requests. The ResponseWrapper
object can provide both the raw json message, as well as a pandas dataframe. The ResponseWrapper
contains additional type information which will create column names and utilize the correct data type for the constructed pandas dataframe.
A client as a small number of general-purpose methods. In alphabetical order:
-
controls
: managment controls for monitoring/configurating the running server -
last
: get the last ticked data value on a channel -
lookup
: lookup a piece of data byid
-
next
: get the next ticked data value on a channel -
send
: send some data onto a channel -
state
: get the value of a given channel's state accumulator
Additionally, a client has some streaming methods available when websockets are configured:
-
stream
: call a callback when a channel ticks -
subscribe
: subscribe to data on a channel -
unsubscribe
: unsubscribe to data on a channel
Let's explore some of the functionality of the basic demo server. To start, we should run the demo server in another process (with the omnibus config):
csp-gateway-start --config-dir=csp_gateway/server/demo +config=omnibus
By default, this will run the server on localhost:8000
.
All the important objects are hoisted to the top level csp_gateway
. Lets import and setup our client.
from csp_gateway import GatewayClient, GatewayClientConfig
config = GatewayClientConfig(host="localhost", port=8000, return_raw_json=False)
client = GatewayClient(config)
The first time we use our client, it will take a little longer than usual as it tries to interrogate the running server's openapi
specification for available methods. Once done, our request will go through, and subsequent requests will leverage this specification. Let's start with some simple status checks. If we're curious about available endpoints, we can navigate to http://localhost:8000/redoc (or generally http://<hostname>:<port>/redoc
if we're running on a different host)
# heartbeat check
client.controls("heartbeat").as_json()
[{'id': '7180742829515',
'timestamp': '2025-03-14T06:00:12.399921',
'name': 'heartbeat',
'status': 'ok',
'data': {},
'data_str': ''}]
# openapi spec
from IPython.display import JSON
JSON(client._openapi_spec)
<IPython.core.display.JSON object>
# machine stats
client.controls("stats").as_json()
[{'id': '7180742829516',
'timestamp': '2025-03-14T06:00:12.562785',
'name': 'stats',
'status': 'ok',
'data': {'cpu': 0.0,
'memory': 63.7,
'memory-total': 36.28,
'pid': 1750281,
'active_threads': 4,
'max_threads': 'unlimited',
'now': '2025-03-14T06:00:12.564110',
'csp-now': '2025-03-14T06:00:12.563004',
'host': 'devqtccrt06',
'user': 'nk12433'},
'data_str': '{"cpu":0.0,"memory":63.7,"memory-total":36.28,"pid":1750281,"active_threads":4,"max_threads":"unlimited","now":"2025-03-14T06:00:12.564110","csp-now":"2025-03-14T06:00:12.563004","host":"devqtccrt06","user":"nk12433"}'}]
Let's look at what channels we have available for last
:
client.last().as_json()
['controls', 'basket', 'never_ticks', 'example', 'example_list', 'str_basket']
client.last("example").as_json()
[{'id': '7182204802295',
'timestamp': '2025-03-14T06:00:12.274734',
'x': 31,
'y': '303030',
'internal_csp_struct': {'z': 12},
'data': [],
'mapping': {},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'}]
client.last("basket").as_json()
[{'id': '7182204802295',
'timestamp': '2025-03-14T06:00:12.274734',
'x': 31,
'y': '303030',
'internal_csp_struct': {'z': 12},
'data': [],
'mapping': {},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'},
{'id': '7182204802292',
'timestamp': '2025-03-14T06:00:12.269265',
'x': 30,
'y': '3030',
'internal_csp_struct': {'z': 12},
'data': [0.918037522903988,
0.3399226261577962,
0.7909028689829906,
0.7039079146913827,
0.8210556057950636,
0.07325613777603324,
0.36257073731882594,
0.3946540193539001,
0.5774311632755368,
0.20316200054623546],
'mapping': {'30': 30},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'},
{'id': '7182204802293',
'timestamp': '2025-03-14T06:00:12.274455',
'x': 30,
'y': '303030',
'internal_csp_struct': {'z': 12},
'data': [0.4562437422860882,
0.9004249706550138,
0.6477939153762935,
0.3803206666410205,
0.775542818358652,
0.021906915016978834,
0.8893453580688346,
0.8277048024826046,
0.46538738841821836,
0.456588879024889],
'mapping': {'30': 30},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'}]
client.last("basket").as_pandas_df()
id | timestamp | x | y | data | dt | d | internal_csp_struct.z | mapping.30 | mapping | |
---|---|---|---|---|---|---|---|---|---|---|
0 | 7182204802295 | 2025-03-14T06:00:12.274734 | 31 | 303030 | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN |
1 | 7182204802292 | 2025-03-14T06:00:12.269265 | 30 | 3030 | [0.918037522903988, 0.3399226261577962, 0.7909... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | 30.0 | NaN |
2 | 7182204802293 | 2025-03-14T06:00:12.274455 | 30 | 303030 | [0.4562437422860882, 0.9004249706550138, 0.647... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | 30.0 | NaN |
State channels are used to perform state accumulation over a number of ticks. The example server doesn't do anything too interesting, but we can access these channels nevertheless.
client.state().as_json()
['example']
client.state("example").as_pandas_df().tail()
# We note that there are a large number of columns in the above dataframe.
# This is because `mapping` is a dict with different keys for eery row.
# To accomodate all of them, the returned pandas dataframe has a column for any key present in the `mapping` attribute of any `ExampleData` Struct
id | timestamp | x | y | data | dt | d | internal_csp_struct.z | mapping.1 | mapping.2 | ... | mapping.22 | mapping.23 | mapping.24 | mapping.25 | mapping.26 | mapping.27 | mapping.28 | mapping.29 | mapping.30 | mapping | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
40 | 7182204802285 | 2025-03-14T06:00:10.264122 | 28 | 282828 | [0.5303914536525036, 0.0010628925807091294, 0.... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | 28.0 | NaN | NaN | NaN |
41 | 7182204802286 | 2025-03-14T06:00:10.264259 | 29 | 282828 | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
42 | 7182204802290 | 2025-03-14T06:00:11.264179 | 29 | 292929 | [0.7784380063762434, 0.7909368694127872, 0.647... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 29.0 | NaN | NaN |
43 | 7182204802294 | 2025-03-14T06:00:12.274565 | 30 | 303030 | [0.847968392664959, 0.34935942519328944, 0.265... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 30.0 | NaN |
44 | 7182204802295 | 2025-03-14T06:00:12.274734 | 31 | 303030 | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 39 columns
We can lookup individual data points using lookup
. This is a bit of a silly example when we're just looking at a single channel, but can be valuable when you have lots of interconnected channels.
# get the last tick, then lookup by id
last = client.last("example").as_json()[0]
last_id = last["id"]
client.lookup("example", last_id).as_json()
[{'id': '7182204802295',
'timestamp': '2025-03-14T06:00:12.274734',
'x': 31,
'y': '303030',
'internal_csp_struct': {'z': 12},
'data': [],
'mapping': {},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'}]
Finally, we can send our own data into the API using send
.
client.send(
"example",
{
"x": 12,
"y": "HEY!",
"internal_csp_struct": {"z": 13}
}
)
client.state("example").as_pandas_df().tail()
id | timestamp | x | y | data | dt | d | internal_csp_struct.z | mapping.1 | mapping.2 | ... | mapping.22 | mapping.23 | mapping.24 | mapping.25 | mapping.26 | mapping.27 | mapping.28 | mapping.29 | mapping.30 | mapping | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
42 | 7182204802290 | 2025-03-14T06:00:11.264179 | 29 | 292929 | [0.7784380063762434, 0.7909368694127872, 0.647... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 29.0 | NaN | NaN |
43 | 7182204802294 | 2025-03-14T06:00:12.274565 | 30 | 303030 | [0.847968392664959, 0.34935942519328944, 0.265... | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | 30.0 | NaN |
44 | 7182204802295 | 2025-03-14T06:00:12.274734 | 31 | 303030 | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
45 | 7182204802296 | 2025-03-14T06:00:13.034311 | 12 | HEY! | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 13 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
46 | 7182204802297 | 2025-03-14T06:00:13.035209 | 13 | HEY! | [] | 2025-03-14T01:59:42.200557 | 2025-03-14 | 12 | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN |
5 rows × 39 columns
The REST API uses pydantic validation for send
requests. Since ExampleData
has a __validators__
attribute defined, the pydantic version of the GatewayStruct has those functions ran for validation before propagating the sent value through the graph. ExampleData
has validation performed that asserts the value of x
is not negative. When we try to pass a negative value in, we get an error on the send, but the graph does not crash. The details of the error are provided in the response.
client.send("example", {"x": -12, "y": "HEY!"})
ServerUnprocessableException: [{'type': 'list_type', 'loc': ['body', 'list[function-wrap[create_instance()]]'], 'msg': 'Input should be a valid list', 'input': {'x': -12, 'y': 'HEY!'}}, {'type': 'value_error', 'loc': ['body', 'function-wrap[create_instance()]', 'x'], 'msg': 'Value error, value must be non-negative.', 'input': -12, 'ctx': {'error': {}}}]
The running GatewayServer
is a synchronous system, and we're interacting it via asynchronous REST
requests. However, we can still perform actions like "wait for the next tick". This can be dangerous and lead to race conditions, but it can still be useful in certain circumstances.
client.next("example").as_json()
[{'id': '7182204802346',
'timestamp': '2025-03-14T06:00:23.264154',
'x': 41,
'y': '414141',
'internal_csp_struct': {'z': 12},
'data': [0.8434439910392343,
0.16425120769202894,
0.4614001200974842,
0.5296539732016515,
0.7793370635405895,
0.8968921920130971,
0.16515287895221997,
0.9002092496268692,
0.15540237095341358,
0.5879171201018687],
'mapping': {'41': 41},
'dt': '2025-03-14T01:59:42.200557',
'd': '2025-03-14'}]
Note that this call will block until the next value ticks.
If our webserver is configured with websockets, we can also stream data out of channels. A simple example that prints out channel data is provided.
client.stream(channels=["example"], callback=print)
{'channel': 'example', 'data': [{'id': '7182204802364', 'timestamp': '2025-03-14T06:00:27.264171', 'x': 45, 'y': '454545', 'internal_csp_struct': {'z': 12}, 'data': [0.6512409372233339, 0.07206425449741505, 0.5459898400764014, 0.9069291031159893, 0.5632205038815109, 0.6358680416497396, 0.4031860150585428, 0.18951576663682146, 0.13029048524663422, 0.6537721971743142], 'mapping': {'45': 45}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802368', 'timestamp': '2025-03-14T06:00:28.264253', 'x': 46, 'y': '464646', 'internal_csp_struct': {'z': 12}, 'data': [0.13347377162286045, 0.14766463082192083, 0.890098581009976, 0.5762928909003212, 0.9784598838743355, 0.9093206966012796, 0.4421107198172203, 0.6351323300210804, 0.8580132723903817, 0.8155427123499257], 'mapping': {'46': 46}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802369', 'timestamp': '2025-03-14T06:00:28.264459', 'x': 47, 'y': '464646', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802373', 'timestamp': '2025-03-14T06:00:29.264267', 'x': 47, 'y': '474747', 'internal_csp_struct': {'z': 12}, 'data': [0.9770241512799153, 0.9637667972653557, 0.9594704907592322, 0.13620074749494915, 0.02682378617576875, 0.21212555291360513, 0.22007092181222787, 0.38504292634018655, 0.9342337231196015, 0.4290203133079068], 'mapping': {'47': 47}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802377', 'timestamp': '2025-03-14T06:00:30.264338', 'x': 48, 'y': '484848', 'internal_csp_struct': {'z': 12}, 'data': [0.892430583670491, 0.12591388868359998, 0.9224444538829644, 0.0029365846224427283, 0.8455103482206909, 0.6064336013949906, 0.7146470440362958, 0.7172194103168975, 0.5344556625030702, 0.12551306544964813], 'mapping': {'48': 48}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802378', 'timestamp': '2025-03-14T06:00:30.264578', 'x': 49, 'y': '484848', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802382', 'timestamp': '2025-03-14T06:00:31.264269', 'x': 49, 'y': '494949', 'internal_csp_struct': {'z': 12}, 'data': [0.7954525130520012, 0.16105077513514243, 0.6697700523760823, 0.18214767845076874, 0.031965065384497615, 0.3704517634058897, 0.8063898928948885, 0.9372302738066902, 0.12448951223205629, 0.3723664774669405], 'mapping': {'49': 49}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
KeyboardInterrupt
All of the above can also be used in an async
fashion. Note that by default, the GatewayClient
class is an alias for the SyncGatewayClient
class. The only differences are:
- all methods are
async
instead of synchronous -
stream
is an infinite generator, rather than callback-based (so takes nocallback
argument)
from csp_gateway import AsyncGatewayClient
async_client= AsyncGatewayClient(config)
# We can subscribe to multiple channels, including dict-baskets
async def print_all():
async for datum in async_client.stream(channels=["example", "example_list", ("basket", "A")]):
print(datum)
await print_all()
{'channel': 'example_list', 'data': [{'id': '7182204802436', 'timestamp': '2025-03-14T06:00:43.264033', 'x': 61, 'y': '616161', 'internal_csp_struct': {'z': 12}, 'data': [0.2012890963221904, 0.702376333618334, 0.361342696585941, 0.7383356341385855, 0.5439924770669536, 0.5348101969493174, 0.7261873522256002, 0.8653648126326041, 0.22990047589634643, 0.6788906270823372], 'mapping': {'61': 61}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802436', 'timestamp': '2025-03-14T06:00:43.264033', 'x': 61, 'y': '616161', 'internal_csp_struct': {'z': 12}, 'data': [0.2012890963221904, 0.702376333618334, 0.361342696585941, 0.7383356341385855, 0.5439924770669536, 0.5348101969493174, 0.7261873522256002, 0.8653648126326041, 0.22990047589634643, 0.6788906270823372], 'mapping': {'61': 61}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802433', 'timestamp': '2025-03-14T06:00:43.263949', 'x': 61, 'y': '61', 'internal_csp_struct': {'z': 12}, 'data': [0.37515205241819904, 0.21653802732210348, 0.6023670041905677, 0.7020115328362944, 0.5672014845851433, 0.3315506604647509, 0.2835119310422646, 0.17365652828157507, 0.7197090506662692, 0.32070439406165585], 'mapping': {'61': 61}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example_list', 'data': [{'id': '7182204802440', 'timestamp': '2025-03-14T06:00:44.264059', 'x': 62, 'y': '626262', 'internal_csp_struct': {'z': 12}, 'data': [0.46296344196914896, 0.535262117154687, 0.8713255531129767, 0.15089077117115202, 0.9314969920967638, 0.49322856675566407, 0.5097354278193875, 0.36542150764786463, 0.0978733899463935, 0.6526308371221453], 'mapping': {'62': 62}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802440', 'timestamp': '2025-03-14T06:00:44.264059', 'x': 62, 'y': '626262', 'internal_csp_struct': {'z': 12}, 'data': [0.46296344196914896, 0.535262117154687, 0.8713255531129767, 0.15089077117115202, 0.9314969920967638, 0.49322856675566407, 0.5097354278193875, 0.36542150764786463, 0.0978733899463935, 0.6526308371221453], 'mapping': {'62': 62}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802437', 'timestamp': '2025-03-14T06:00:44.263975', 'x': 62, 'y': '62', 'internal_csp_struct': {'z': 12}, 'data': [0.940523191216232, 0.14852620784066317, 0.08189176013369992, 0.9043729968792783, 0.05089580688345152, 0.7942753901732218, 0.25601515448071055, 0.708127323757491, 0.42466967147061263, 0.1237637046040877], 'mapping': {'62': 62}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802441', 'timestamp': '2025-03-14T06:00:44.264377', 'x': 63, 'y': '626262', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802441', 'timestamp': '2025-03-14T06:00:44.264377', 'x': 63, 'y': '626262', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example_list', 'data': [{'id': '7182204802445', 'timestamp': '2025-03-14T06:00:45.264058', 'x': 63, 'y': '636363', 'internal_csp_struct': {'z': 12}, 'data': [0.31908694135855364, 0.3778381445552632, 0.7861888413413884, 0.9574250161776887, 0.5833248271672732, 0.308015510869482, 0.8170552095029715, 0.3533446051973852, 0.565398159234985, 0.9591750226310537], 'mapping': {'63': 63}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802445', 'timestamp': '2025-03-14T06:00:45.264058', 'x': 63, 'y': '636363', 'internal_csp_struct': {'z': 12}, 'data': [0.31908694135855364, 0.3778381445552632, 0.7861888413413884, 0.9574250161776887, 0.5833248271672732, 0.308015510869482, 0.8170552095029715, 0.3533446051973852, 0.565398159234985, 0.9591750226310537], 'mapping': {'63': 63}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802442', 'timestamp': '2025-03-14T06:00:45.263969', 'x': 63, 'y': '63', 'internal_csp_struct': {'z': 12}, 'data': [0.26219215598319245, 0.7876415886108106, 0.46734385893262653, 0.5875585649183716, 0.6973450587166122, 0.19938357748148694, 0.5681164164813136, 0.08582575356430155, 0.5822429915710623, 0.032509795763884575], 'mapping': {'63': 63}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example_list', 'data': [{'id': '7182204802449', 'timestamp': '2025-03-14T06:00:46.264050', 'x': 64, 'y': '646464', 'internal_csp_struct': {'z': 12}, 'data': [0.8423317626185829, 0.20973759581109863, 0.5292314592966805, 0.8273340088284135, 0.16798011294997617, 0.3954567336148307, 0.4363356424438266, 0.15038572422882712, 0.30525781171354893, 0.2066455497558468], 'mapping': {'64': 64}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802449', 'timestamp': '2025-03-14T06:00:46.264050', 'x': 64, 'y': '646464', 'internal_csp_struct': {'z': 12}, 'data': [0.8423317626185829, 0.20973759581109863, 0.5292314592966805, 0.8273340088284135, 0.16798011294997617, 0.3954567336148307, 0.4363356424438266, 0.15038572422882712, 0.30525781171354893, 0.2066455497558468], 'mapping': {'64': 64}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802446', 'timestamp': '2025-03-14T06:00:46.263966', 'x': 64, 'y': '64', 'internal_csp_struct': {'z': 12}, 'data': [0.5186648328191604, 0.20600018613504822, 0.2517255629965035, 0.2027172299603618, 0.6973958971974537, 0.018533961127689347, 0.8831800860672222, 0.15443494355861742, 0.7879460672351232, 0.5737498259238871], 'mapping': {'64': 64}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802450', 'timestamp': '2025-03-14T06:00:46.264341', 'x': 65, 'y': '646464', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802450', 'timestamp': '2025-03-14T06:00:46.264341', 'x': 65, 'y': '646464', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example_list', 'data': [{'id': '7182204802454', 'timestamp': '2025-03-14T06:00:47.264053', 'x': 65, 'y': '656565', 'internal_csp_struct': {'z': 12}, 'data': [0.38361199716851, 0.4318530809990534, 0.3327373711769688, 0.19177499312477841, 0.8238340463975228, 0.3122577782035033, 0.26085183935102385, 0.12676280253692418, 0.27222241778232015, 0.8142830554492966], 'mapping': {'65': 65}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802454', 'timestamp': '2025-03-14T06:00:47.264053', 'x': 65, 'y': '656565', 'internal_csp_struct': {'z': 12}, 'data': [0.38361199716851, 0.4318530809990534, 0.3327373711769688, 0.19177499312477841, 0.8238340463975228, 0.3122577782035033, 0.26085183935102385, 0.12676280253692418, 0.27222241778232015, 0.8142830554492966], 'mapping': {'65': 65}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802451', 'timestamp': '2025-03-14T06:00:47.263966', 'x': 65, 'y': '65', 'internal_csp_struct': {'z': 12}, 'data': [0.0892006794893967, 0.07876938817599266, 0.9480755640114016, 0.8956409788136256, 0.1765617680441619, 0.34959327017659225, 0.5691499047953102, 0.6197869710008492, 0.4247627740185159, 0.22229884776814335], 'mapping': {'65': 65}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example_list', 'data': [{'id': '7182204802458', 'timestamp': '2025-03-14T06:00:48.264056', 'x': 66, 'y': '666666', 'internal_csp_struct': {'z': 12}, 'data': [0.785907903315688, 0.20499171133424998, 0.1997585736271853, 0.8400504706317495, 0.5078353527827971, 0.17751926740421575, 0.240514889413168, 0.7795065353794545, 0.10821747119526537, 0.013346638048011616], 'mapping': {'66': 66}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802458', 'timestamp': '2025-03-14T06:00:48.264056', 'x': 66, 'y': '666666', 'internal_csp_struct': {'z': 12}, 'data': [0.785907903315688, 0.20499171133424998, 0.1997585736271853, 0.8400504706317495, 0.5078353527827971, 0.17751926740421575, 0.240514889413168, 0.7795065353794545, 0.10821747119526537, 0.013346638048011616], 'mapping': {'66': 66}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802455', 'timestamp': '2025-03-14T06:00:48.263975', 'x': 66, 'y': '66', 'internal_csp_struct': {'z': 12}, 'data': [0.9441185853333258, 0.7659205422168367, 0.5186970325300565, 0.7140712043958034, 0.8653320532574393, 0.8233499006198564, 0.5896847424112025, 0.07401817792364396, 0.17173762100190504, 0.864687792136789], 'mapping': {'66': 66}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'example', 'data': [{'id': '7182204802459', 'timestamp': '2025-03-14T06:00:48.264360', 'x': 67, 'y': '666666', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'basket', 'key': 'A', 'data': [{'id': '7182204802459', 'timestamp': '2025-03-14T06:00:48.264360', 'x': 67, 'y': '666666', 'internal_csp_struct': {'z': 12}, 'data': [], 'mapping': {}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
CancelledError
# We can susbscribe to every tick from a dict basket by just subscribing to the full basket
async def print_all_basket():
async for datum in async_client.stream(channels=["str_basket"]):
print(datum)
await print_all_basket()
{'channel': 'str_basket', 'key': 'a', 'data': [{'id': '7182204802482', 'timestamp': '2025-03-14T06:00:54.263974', 'x': 72, 'y': '72', 'internal_csp_struct': {'z': 12}, 'data': [0.0024343396429761244, 0.25557971088785525, 0.8830889612103591, 0.5248708862100656, 0.13301440206288329, 0.0613374033071844, 0.9533501115434322, 0.17519376229750483, 0.20826938545917772, 0.3154244464812893], 'mapping': {'72': 72}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'b', 'data': [{'id': '7182204802483', 'timestamp': '2025-03-14T06:00:54.264023', 'x': 72, 'y': '7272', 'internal_csp_struct': {'z': 12}, 'data': [0.8477714975000878, 0.8761447163517748, 0.4132611178713649, 0.035190170106964236, 0.6786254800475836, 0.9475667654798842, 0.5866246994077503, 0.26298570997111104, 0.31639906057837064, 0.3663114982586084], 'mapping': {'72': 72}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'c', 'data': [{'id': '7182204802484', 'timestamp': '2025-03-14T06:00:54.264041', 'x': 72, 'y': '727272', 'internal_csp_struct': {'z': 12}, 'data': [0.3332323138368375, 0.05696328615646484, 0.23548236793906674, 0.2820311457311522, 0.9589706357912199, 0.44038637040590844, 0.19630430868230497, 0.7453123881812489, 0.1878259296575574, 0.17223653057513189], 'mapping': {'72': 72}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'a', 'data': [{'id': '7182204802487', 'timestamp': '2025-03-14T06:00:55.263971', 'x': 73, 'y': '73', 'internal_csp_struct': {'z': 12}, 'data': [0.6919631440411455, 0.4728617807619395, 0.0003944547125812603, 0.011758757622944871, 0.09775418165142358, 0.9825827730540471, 0.869142195037153, 0.06360846203630244, 0.6391038358448057, 0.18918471862707165], 'mapping': {'73': 73}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'b', 'data': [{'id': '7182204802488', 'timestamp': '2025-03-14T06:00:55.264023', 'x': 73, 'y': '7373', 'internal_csp_struct': {'z': 12}, 'data': [0.23318761968678847, 0.7916938531654325, 0.16766945067832806, 0.30717503529152856, 0.7234609518781409, 0.6761783642820521, 0.012291838679474254, 0.3734093437402387, 0.25193367414091183, 0.4116290421307852], 'mapping': {'73': 73}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'c', 'data': [{'id': '7182204802489', 'timestamp': '2025-03-14T06:00:55.264041', 'x': 73, 'y': '737373', 'internal_csp_struct': {'z': 12}, 'data': [0.9995663904683157, 0.49037285862321134, 0.9360403966245218, 0.32907171896712595, 0.8706475080400187, 0.9358547470908197, 0.6094950522388487, 0.3187147239906233, 0.5146210935507332, 0.2468259549948888], 'mapping': {'73': 73}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'a', 'data': [{'id': '7182204802491', 'timestamp': '2025-03-14T06:00:56.263987', 'x': 74, 'y': '74', 'internal_csp_struct': {'z': 12}, 'data': [0.30780427957177736, 0.31783225533438253, 0.28974485377085746, 0.8056785399315933, 0.6550343960061931, 0.51147587370349, 0.22918318357951206, 0.27483544636782764, 0.1617784534805391, 0.12615374449682082], 'mapping': {'74': 74}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'b', 'data': [{'id': '7182204802492', 'timestamp': '2025-03-14T06:00:56.264040', 'x': 74, 'y': '7474', 'internal_csp_struct': {'z': 12}, 'data': [0.7597865185560577, 0.9542811639842493, 0.3548238255188084, 0.5497091911407666, 0.2103980379131476, 0.9282153309075862, 0.019933785131218018, 0.07818556433746526, 0.8906613298984217, 0.4142275174628044], 'mapping': {'74': 74}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'c', 'data': [{'id': '7182204802493', 'timestamp': '2025-03-14T06:00:56.264059', 'x': 74, 'y': '747474', 'internal_csp_struct': {'z': 12}, 'data': [0.5351854446981592, 0.7247690029219567, 0.8073854595040114, 0.7157206622262171, 0.4352917223246313, 0.4369240091155152, 0.16633677865466623, 0.39403050678439466, 0.5964420480684727, 0.4549142654097128], 'mapping': {'74': 74}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'a', 'data': [{'id': '7182204802496', 'timestamp': '2025-03-14T06:00:57.263968', 'x': 75, 'y': '75', 'internal_csp_struct': {'z': 12}, 'data': [0.5464599879444142, 0.721937878646433, 0.8743734166377515, 0.19869546159445028, 0.13465567320565885, 0.13731281812355312, 0.985981130222794, 0.7543303190330615, 0.17166394918759065, 0.7745127544725419], 'mapping': {'75': 75}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'b', 'data': [{'id': '7182204802497', 'timestamp': '2025-03-14T06:00:57.264016', 'x': 75, 'y': '7575', 'internal_csp_struct': {'z': 12}, 'data': [0.014886231617977641, 0.8035620841240536, 0.6303792158456698, 0.3810092650960091, 0.36235076847179437, 0.6273491033528601, 0.04515741170281928, 0.40411733708766073, 0.5610236907135676, 0.8084273295250559], 'mapping': {'75': 75}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
{'channel': 'str_basket', 'key': 'c', 'data': [{'id': '7182204802498', 'timestamp': '2025-03-14T06:00:57.264034', 'x': 75, 'y': '757575', 'internal_csp_struct': {'z': 12}, 'data': [0.14440123791521808, 0.41124092584685856, 0.558344424856301, 0.7197882892005704, 0.6791006750064388, 0.9625438604579102, 0.9079986744434172, 0.5810653358542905, 0.42340551567499196, 0.6309477160315278], 'mapping': {'75': 75}, 'dt': '2025-03-14T01:59:42.200557', 'd': '2025-03-14'}]}
CancelledError
This wiki is autogenerated. To made updates, open a PR against the original source file in docs/wiki
.
Get Started
Key Components
For Developers
Modules
- API/UI Modules
- Logging Modules
- Replay Engine Modules
- Utility Modules
For Contributors