Skip to content

Commit 261a31d

Browse files
committed
docs: python & fix some rust (#930)
1 parent 811e3de commit 261a31d

15 files changed

+273
-13
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,7 +131,7 @@ Seamlessly integrate ActorCore with your favorite frameworks, languages, and too
131131
### Clients
132132
- <img src="docs/images/clients/javascript.svg" height="16" alt="JavaScript" />&nbsp;&nbsp;[JavaScript](/clients/javascript)
133133
- <img src="docs/images/clients/typescript.svg" height="16" alt="TypeScript" />&nbsp;&nbsp;[TypeScript](/clients/javascript)
134-
- <img src="docs/images/clients/python.svg" height="16" alt="Python" />&nbsp;&nbsp;[Python](https://github.com/rivet-gg/actor-core/issues/900) *(Available In April)*
134+
- <img src="docs/images/clients/python.svg" height="16" alt="Python" />&nbsp;&nbsp;[Python](/clients/python)
135135
- <img src="docs/images/clients/rust.svg" height="16" alt="Rust" />&nbsp;&nbsp;[Rust](/clients/rust)
136136

137137
### Integrations

clients/python/Cargo.toml

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,16 @@
1+
# Python client code is generated by
2+
# this package, with the aid of pyo3
3+
#
4+
# This package turns into the python
5+
# pypi actor-core-client package
16
[package]
2-
name = "python_actor_core_client"
7+
name = "python-actor-core-client"
38
version = "0.8.0"
49
edition = "2021"
10+
publish = false
511

612
[lib]
7-
name = "python_actor_core_client"
13+
name = "actor_core_client"
814
crate-type = ["cdylib"]
915

1016
[dependencies]

clients/python/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[project]
2-
name = "python_actor_core_client"
2+
name = "actor-core-client"
33
version = "0.8.0"
44
authors = [
55
{ name="Rivet Gaming, LLC", email="developer@rivet.gg" },

clients/python/src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ mod simple;
66
mod events;
77

88
#[pymodule]
9-
fn python_actor_core_client(m: &Bound<'_, PyModule>) -> PyResult<()> {
9+
fn actor_core_client(m: &Bound<'_, PyModule>) -> PyResult<()> {
1010
simple::init_module(m)?;
1111
events::init_module(m)?;
1212

clients/python/tests/test_e2e_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import asyncio
22
import pytest
3-
from python_actor_core_client import AsyncClient as ActorClient
3+
from actor_core_client import AsyncClient as ActorClient
44
from common import start_mock_server, get_free_port, logger
55

66
@pytest.mark.asyncio

clients/python/tests/test_e2e_simple_async.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import asyncio
22
import pytest
3-
from python_actor_core_client import AsyncSimpleClient as ActorClient
3+
from actor_core_client import AsyncSimpleClient as ActorClient
44
from common import start_mock_server, logger
55

66
async def do_oneoff_increment(client):

clients/python/tests/test_e2e_simple_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from python_actor_core_client import SimpleClient as ActorClient
1+
from actor_core_client import SimpleClient as ActorClient
22
from common import start_mock_server, logger
33

44

clients/python/tests/test_e2e_sync.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from python_actor_core_client import Client as ActorClient
1+
from actor_core_client import Client as ActorClient
22
from common import start_mock_server, logger
33

44
def test_e2e_sync():

docs/clients/python.mdx

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
---
2+
title: Python
3+
icon: python
4+
---
5+
6+
import MvpWarning from "/snippets/mvp-warning.mdx";
7+
import StepDefineActor from "/snippets/step-define-actor.mdx";
8+
import StepRunStudio from "/snippets/step-run-studio.mdx";
9+
import StepDeploy from "/snippets/step-deploy.mdx";
10+
import SetupNextSteps from "/snippets/setup-next-steps.mdx";
11+
12+
The ActorCore Python client provides a way to connect to and interact with actors from Python applications.
13+
14+
<MvpWarning />
15+
16+
## Quickstart
17+
18+
<Steps>
19+
<Step title="Create a new Python project">
20+
Create a new directory for your project:
21+
22+
```sh
23+
mkdir my-app
24+
cd my-app
25+
```
26+
27+
It's recommended to create a virtual environment:
28+
```sh
29+
python -m venv venv
30+
source venv/bin/activate # On Windows use: venv\Scripts\activate
31+
```
32+
</Step>
33+
34+
<Step title="Add dependencies">
35+
Install the ActorCore client package:
36+
37+
```sh
38+
pip install actor-core-client
39+
```
40+
</Step>
41+
42+
<StepDefineActor />
43+
44+
<Step title="Create your client">
45+
Create a new file `main.py`:
46+
47+
<CodeGroup>
48+
```python Async
49+
import asyncio
50+
from actor_core_client import AsyncClient
51+
52+
async def main():
53+
# Replace with your endpoint URL after deployment
54+
client = AsyncClient("http://localhost:6420")
55+
56+
# Get or create an actor instance
57+
counter = await client.get("counter")
58+
59+
# Subscribe to events using callback
60+
def on_new_count(msg):
61+
print(f"Event: {msg}")
62+
63+
counter.on_event("newCount", on_new_count)
64+
65+
# Call an action
66+
result = await counter.action("increment", 5)
67+
print(f"Action result: {result}")
68+
69+
# Wait to receive events
70+
await asyncio.sleep(1)
71+
72+
# Clean up
73+
await counter.disconnect()
74+
75+
if __name__ == "__main__":
76+
asyncio.run(main())
77+
```
78+
79+
```python Sync
80+
from actor_core_client import Client
81+
82+
# Replace with your endpoint URL after deployment
83+
client = Client("http://localhost:6420")
84+
85+
# Get or create an actor instance
86+
counter = client.get("counter")
87+
88+
# Subscribe to events using callback
89+
def on_new_count(msg):
90+
print(f"Event: {msg}")
91+
92+
# Clean up once we receive our event
93+
counter.disconnect()
94+
95+
counter.on_event("newCount", on_new_count)
96+
97+
# Call an action
98+
result = counter.action("increment", 5)
99+
print(f"Action result: {result}")
100+
101+
# Clean is handled on by on_new_count
102+
```
103+
</CodeGroup>
104+
105+
In the code above, subscription is done with `on_event` callbacks, but you can also
106+
subscribe directly with `receive()` calls, using the `SimpleClient` (and `AsyncSimpleClient`)
107+
interfaces. See our [sample usage](https://github.com/rivet-gg/actor-core/tree/main/clients/python/tests/test_e2e_simple_async.py) for more details.
108+
</Step>
109+
110+
<StepRunStudio />
111+
112+
<Step title="Run your client">
113+
In a separate terminal, run your Python code:
114+
115+
```sh
116+
python main.py
117+
```
118+
119+
You should see output like:
120+
```
121+
Event: 5
122+
Action result: 5
123+
```
124+
125+
Run it again to see the state update.
126+
</Step>
127+
128+
<StepDeploy />
129+
</Steps>
130+
131+
<SetupNextSteps />

docs/concepts/interacting-with-actors.mdx

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,13 @@ let client = Client::new(
2828
EncodingKind::Cbor, // Encoding (Json or Cbor)
2929
);
3030
```
31+
32+
```python Python (Callbacks)
33+
from actor_core_client import AsyncClient as ActorClient
34+
35+
# Create a client with the connection address
36+
client = ActorClient("http://localhost:6420")
37+
```
3138
</CodeGroup>
3239

3340
<Tip>See the setup guide for your platform for details on how to get the connection address.</Tip>
@@ -76,6 +83,17 @@ room.action("sendMessage", vec![json!("Alice"), json!("Hello everyone!")])
7683
.await
7784
.expect("Failed to send message");
7885
```
86+
87+
```python Python (Callbacks)
88+
# Connect to a chat room for the "general" channel
89+
room = await client.get("chatRoom", tags=[
90+
("name", "chat_room"),
91+
("channel", "general")
92+
])
93+
94+
# Now you can call methods on the actor
95+
await room.action("sendMessage", ["Alice", "Hello everyone!"])
96+
```
7997
</CodeGroup>
8098

8199
### `create(opts)` - Explicitly Create New
@@ -125,6 +143,16 @@ doc.action("initializeDocument", vec![json!("My New Document")])
125143
.await
126144
.expect("Failed to initialize document");
127145
```
146+
147+
```python Python (Callbacks)
148+
# Create a new document actor
149+
doc = await client.get("myDocument", tags=[
150+
("name", "my_document"),
151+
("docId", "123")
152+
])
153+
154+
await doc.action("initializeDocument", ["My New Document"])
155+
```
128156
</CodeGroup>
129157

130158
### `getWithId(id, opts)` - Connect by ID
@@ -148,7 +176,7 @@ let my_actor_id = "55425f42-82f8-451f-82c1-6227c83c9372";
148176
let options = GetWithIdOptions {
149177
params: None,
150178
};
151-
let doc = client.get_with_id("myDocument", my_actor_id, options)
179+
let doc = client.get_with_id(my_actor_id, options)
152180
.await
153181
.expect("Failed to connect to document");
154182

@@ -157,6 +185,14 @@ doc.action("updateContent", vec![json!("Updated content")])
157185
.await
158186
.expect("Failed to update document");
159187
```
188+
189+
```python Python (Callbacks)
190+
# Connect to a specific actor by its ID
191+
my_actor_id = "55425f42-82f8-451f-82c1-6227c83c9372"
192+
doc = await client.get_with_id(my_actor_id)
193+
194+
await doc.action("updateContent", ["Updated content"])
195+
```
160196
</CodeGroup>
161197

162198
<Note>
@@ -208,6 +244,22 @@ game_room.action("updateSettings", vec![settings])
208244
.await
209245
.expect("Failed to update settings");
210246
```
247+
248+
```python Python (Callbacks)
249+
# Call an action
250+
result = await math_utils.action("multiplyByTwo", [5])
251+
print(result) # 10
252+
253+
# Call an action with multiple parameters
254+
await chat_room.action("sendMessage", ["Alice", "Hello everyone!"])
255+
256+
# Call an action with an object parameter
257+
await game_room.action("updateSettings", [{
258+
"maxPlayers": 10,
259+
"timeLimit": 300,
260+
"gameMode": "capture-the-flag"
261+
}])
262+
```
211263
</CodeGroup>
212264

213265
<Note>
@@ -256,6 +308,24 @@ game_room.on_event("stateUpdate", move |args| {
256308
game_ui_clone.update(game_state);
257309
}).await;
258310
```
311+
312+
```python Python (Callbacks)
313+
# Listen for new chat messages
314+
def handle_message(message):
315+
sender = message["sender"]
316+
text = message["text"]
317+
print(f"{sender}: {text}")
318+
# Update UI with message data
319+
320+
chat_room.on_event("newMessage", handle_message)
321+
322+
# Listen for game state updates
323+
def handle_state_update(game_state):
324+
# Update UI with new game state
325+
update_game_ui(game_state)
326+
327+
game_room.on_event("stateUpdate", handle_state_update)
328+
```
259329
</CodeGroup>
260330

261331
### `once(eventName, callback)` - One-time Listening
@@ -274,6 +344,15 @@ actor.once("requestApproved", () => {
274344
```rust Rust
275345
// `once` is not implemented in Rust
276346
```
347+
348+
```python Python (Callbacks)
349+
# Listen for when a request is approved
350+
def handle_approval():
351+
show_approval_notification()
352+
unlock_features()
353+
354+
actor.on_event("requestApproved", handle_approval)
355+
```
277356
</CodeGroup>
278357

279358
## Connection Options
@@ -318,6 +397,18 @@ let chat_room = client.get("chatRoom", options)
318397
.await
319398
.expect("Failed to connect to chat room");
320399
```
400+
401+
```python Python (Callbacks)
402+
chat_room = await client.get(
403+
"chatRoom",
404+
tags=[("channel", "super-secret")],
405+
params={
406+
"userId": "1234",
407+
"authToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
408+
"displayName": "Alice"
409+
}
410+
)
411+
```
321412
</CodeGroup>
322413

323414
The actor can access these parameters in the `onBeforeConnect` or `createConnState` hook:
@@ -391,6 +482,19 @@ let client = Client::new(
391482

392483
// Rust does not support accepting multiple transports
393484
```
485+
486+
```python Python (Callbacks)
487+
from actor_core_client import AsyncClient as ActorClient
488+
489+
# Example with all client options
490+
client = ActorClient(
491+
"https://actors.example.com",
492+
"websocket" # or "sse"
493+
"cbor", # or "json"
494+
)
495+
496+
# Python does not support accepting multiple transports
497+
```
394498
</CodeGroup>
395499

396500
### `encoding`
@@ -490,6 +594,11 @@ actor.disconnect().await;
490594
// Or explicitly drop it with:
491595
drop(client);
492596
```
597+
598+
```python Python (Callbacks)
599+
# Disconnect from the actor
600+
await actor.disconnect()
601+
```
493602
</CodeGroup>
494603

495604
## Offline and Auto-Reconnection

0 commit comments

Comments
 (0)