Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ pip install getstream[webrtc]
uv add 'getstream[webrtc]'
```

## Migrating from stream-chat?

If you are currently using [`stream-chat`](https://github.com/GetStream/stream-chat-python), we have a detailed migration guide with side-by-side code examples for common Chat use cases. See the [Migration Guide](docs/migration-from-stream-chat-python/README.md).
Comment on lines +37 to +39
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
fd '^(pyproject\.toml|setup\.cfg|setup\.py)$' -x sh -c '
  echo "== {} ==";
  rg -n -C2 "readme|long_description|long_description_content_type" "{}" || true
'

Repository: GetStream/stream-py

Length of output: 214


Switch the migration guide link to an absolute GitHub URL.

README.md is configured as the package long description in pyproject.toml, which means it displays on PyPI. The relative link docs/migration-from-stream-chat-python/README.md will be broken for users viewing the docs on PyPI, since the docs directory is not included in the distributed package. Use an absolute GitHub URL instead: https://github.com/GetStream/stream-py/blob/main/docs/migration-from-stream-chat-python/README.md or similar.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@README.md` around lines 37 - 39, Update the Markdown link in README.md that
currently points to the relative docs path
`docs/migration-from-stream-chat-python/README.md` so it uses the absolute
GitHub URL (for example
`https://github.com/GetStream/stream-py/blob/main/docs/migration-from-stream-chat-python/README.md`);
specifically replace the link target in the "Migration Guide" markdown link in
the "Migrating from stream-chat?" section so the README long description on PyPI
resolves correctly.


## Usage

To get started, you need to import the `Stream` class from the library and create a new instance with your API key and secret:
Expand Down
115 changes: 115 additions & 0 deletions docs/migration-from-stream-chat-python/01-setup-and-auth.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# Setup and Authentication

This guide shows how to migrate setup and authentication code from `stream-chat` to `getstream`.

## Installation

**Before (stream-chat):**

```bash
pip install stream-chat
```

**After (getstream):**

```bash
pip install getstream
```

## Client Initialization

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
```

**Key changes:**
- Import changes from `stream_chat.StreamChat` to `getstream.Stream`
- The new SDK auto-loads `STREAM_API_KEY` and `STREAM_API_SECRET` from the environment or a `.env` file, so you can also initialize with `Stream()`

## Async Client

**Before (stream-chat):**

```python
from stream_chat import StreamChatAsync

async with StreamChatAsync(api_key="your-api-key", api_secret="your-api-secret") as client:
response = await client.get_app_settings()
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
async_client = client.as_async()
```

**Key changes:**
- No separate `StreamChatAsync` class; call `client.as_async()` on the sync client instead
- The async client has full parity with the sync client

## Creating a User Token

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
token = client.create_token("user-1", expiration=3600)
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
token = client.create_token(user_id="user-1", expiration=3600)
```

**Key changes:**
- Method name is the same (`create_token`), but uses explicit keyword arguments

## Environment Variables

**Before (stream-chat):**

| Variable | Purpose |
|----------|---------|
| `STREAM_CHAT_TIMEOUT` | Request timeout |
| `STREAM_CHAT_URL` | Custom base URL |

**After (getstream):**

| Variable | Purpose |
|----------|---------|
| `STREAM_API_KEY` | API key (auto-loaded) |
| `STREAM_API_SECRET` | API secret (auto-loaded) |
| `STREAM_BASE_URL` | Custom base URL |
| `STREAM_TIMEOUT` | Request timeout |

## Sub-clients

The new SDK organizes methods into product-specific sub-clients accessed from the main client:

| Sub-client | Access | Description |
|------------|--------|-------------|
| Chat | `client.chat` | Channels, messages, reactions |
| Video | `client.video` | Calls, call types |
| Moderation | `client.moderation` | Ban, mute, flag |
| Feeds | `client.feeds` | Activity feeds (sync only) |
250 changes: 250 additions & 0 deletions docs/migration-from-stream-chat-python/02-users.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
# Users

This guide shows how to migrate user management code from `stream-chat` to `getstream`.

## Upsert a Single User

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_user({"id": "user-1", "name": "Alice", "role": "admin"})
```

**After (getstream):**

```python
from getstream import Stream
from getstream.models import UserRequest

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_users(
UserRequest(id="user-1", name="Alice", role="admin")
)
```

**Key changes:**
- Plain dicts replaced by typed `UserRequest` objects
- Method is `upsert_users()` (accepts one or more `UserRequest` arguments)

## Upsert Multiple Users

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_users([
{"id": "user-1", "name": "Alice"},
{"id": "user-2", "name": "Bob"},
])
```

**After (getstream):**

```python
from getstream import Stream
from getstream.models import UserRequest

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_users(
UserRequest(id="user-1", name="Alice"),
UserRequest(id="user-2", name="Bob"),
)
```

**Key changes:**
- Pass multiple `UserRequest` arguments instead of a list of dicts

## Custom Fields

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_user({
"id": "user-1",
"name": "Alice",
"favorite_color": "blue",
"premium": True,
})
```

**After (getstream):**

```python
from getstream import Stream
from getstream.models import UserRequest

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.upsert_users(
UserRequest(
id="user-1",
name="Alice",
custom={"favorite_color": "blue", "premium": True},
)
)
```

**Key changes:**
- Custom fields go in the `custom` dict instead of being mixed with standard fields at the top level

## Query Users

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.query_users(
filter_conditions={"role": {"$eq": "admin"}},
sort=[{"field": "created_at", "direction": -1}],
limit=10,
)
```

**After (getstream):**

```python
from getstream import Stream
from getstream.models import QueryUsersPayload, SortParamRequest

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.query_users(
QueryUsersPayload(
filter_conditions={"role": {"$eq": "admin"}},
sort=[SortParamRequest(field="created_at", direction=-1)],
limit=10,
)
)
```

**Key changes:**
- Filter and sort are wrapped in `QueryUsersPayload` and `SortParamRequest` models
- Sort uses `SortParamRequest` objects instead of plain dicts

## Partial Update User

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.update_user_partial({
"id": "user-1",
"set": {"name": "Alice Updated", "status": "online"},
"unset": ["old_field"],
})
```

**After (getstream):**

```python
from getstream import Stream
from getstream.models import UpdateUserPartialRequest

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.update_users_partial(
users=[
UpdateUserPartialRequest(
id="user-1",
set={"name": "Alice Updated", "status": "online"},
unset=["old_field"],
)
]
)
```

**Key changes:**
- Method renamed from `update_user_partial()` to `update_users_partial()`
- Takes a list of `UpdateUserPartialRequest` objects via the `users` parameter

## Deactivate User

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.deactivate_user("user-1")
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.deactivate_user(
user_id="user-1",
mark_messages_deleted=False,
)
```

**Key changes:**
- Uses explicit keyword arguments instead of positional string

## Deactivate Multiple Users

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.deactivate_users(["user-1", "user-2"])
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.deactivate_users(user_ids=["user-1", "user-2"])
```

**Key changes:**
- Uses `user_ids` keyword argument instead of positional list

## Delete Users

**Before (stream-chat):**

```python
from stream_chat import StreamChat

client = StreamChat(api_key="your-api-key", api_secret="your-api-secret")
response = client.delete_users(
["user-1", "user-2"],
delete_type="hard",
conversations="hard",
messages="hard",
)
```

**After (getstream):**

```python
from getstream import Stream

client = Stream(api_key="your-api-key", api_secret="your-api-secret")
response = client.delete_users(
user_ids=["user-1", "user-2"],
user="hard",
conversations="hard",
messages="hard",
)
```

**Key changes:**
- Uses `user_ids` keyword argument instead of positional list
- `delete_type` parameter renamed to `user`
Loading