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
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
omit = stream/tests/*
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@ jobs:
name: 🧪 Test & lint
runs-on: ubuntu-latest
strategy:
max-parallel: 1
matrix:
python: ["3.7", "3.8", "3.9", "3.10"]
python: ['3.7', '3.8', '3.9', '3.10']
steps:
- uses: actions/checkout@v3
with:
Expand All @@ -30,7 +31,7 @@ jobs:
python-version: ${{ matrix.python }}

- name: Install deps with ${{ matrix.python }}
run: pip install ".[test, ci]"
run: pip install -q ".[test, ci]"

- name: Lint with ${{ matrix.python }}
if: ${{ matrix.python == '3.7' }}
Expand Down
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ docs/_build/
secrets.*sh
.idea
.vscode/
.python-version

.venv
.envrc
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,4 @@ check: lint test ## Run linters + tests

reviewdog:
black --check --diff --quiet stream | reviewdog -f=diff -f.diff.strip=0 -filter-mode="diff_context" -name=black -reporter=github-pr-review
flake8 --ignore=E501,W503 stream | reviewdog -f=flake8 -name=flake8 -reporter=github-pr-review
flake8 --ignore=E501,W503,E225,W293,F401 stream | reviewdog -f=flake8 -name=flake8 -reporter=github-pr-review
126 changes: 126 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,9 +163,135 @@ events = [impression, engagement]
redirect_url = client.create_redirect_url('http://google.com/', 'user_id', events)
```

### Async code usage
```python
import datetime
import stream
client = stream.connect('YOUR_API_KEY', 'API_KEY_SECRET', use_async=True)


# Create a new client specifying data center location
client = stream.connect('YOUR_API_KEY', 'API_KEY_SECRET', location='us-east', use_async=True)
# Find your API keys here https://getstream.io/dashboard/

# Create a feed object
user_feed_1 = client.feed('user', '1')

# Get activities from 5 to 10 (slow pagination)
result = await user_feed_1.get(limit=5, offset=5)
# (Recommended & faster) Filter on an id less than the given UUID
result = await user_feed_1.get(limit=5, id_lt="e561de8f-00f1-11e4-b400-0cc47a024be0")

# Create a new activity
activity_data = {'actor': 1, 'verb': 'tweet', 'object': 1, 'foreign_id': 'tweet:1'}
activity_response = await user_feed_1.add_activity(activity_data)
# Create a bit more complex activity
activity_data = {'actor': 1, 'verb': 'run', 'object': 1, 'foreign_id': 'run:1',
'course': {'name': 'Golden Gate park', 'distance': 10},
'participants': ['Thierry', 'Tommaso'],
'started_at': datetime.datetime.now()
}
await user_feed_1.add_activity(activity_data)

# Remove an activity by its id
await user_feed_1.remove_activity("e561de8f-00f1-11e4-b400-0cc47a024be0")
# or by foreign id
await user_feed_1.remove_activity(foreign_id='tweet:1')

# Follow another feed
await user_feed_1.follow('flat', '42')

# Stop following another feed
await user_feed_1.unfollow('flat', '42')

# List followers/following
following = await user_feed_1.following(offset=0, limit=2)
followers = await user_feed_1.followers(offset=0, limit=10)

# Creates many follow relationships in one request
follows = [
{'source': 'flat:1', 'target': 'user:1'},
{'source': 'flat:1', 'target': 'user:2'},
{'source': 'flat:1', 'target': 'user:3'}
]
await client.follow_many(follows)

# Batch adding activities
activities = [
{'actor': 1, 'verb': 'tweet', 'object': 1},
{'actor': 2, 'verb': 'watch', 'object': 3}
]
await user_feed_1.add_activities(activities)

# Add an activity and push it to other feeds too using the `to` field
activity = {
"actor":"1",
"verb":"like",
"object":"3",
"to":["user:44", "user:45"]
}
await user_feed_1.add_activity(activity)

# Retrieve an activity by its ID
await client.get_activities(ids=[activity_id])

# Retrieve an activity by the combination of foreign_id and time
await client.get_activities(foreign_id_times=[
(foreign_id, activity_time),
])

# Enrich while getting activities
await client.get_activities(ids=[activity_id], enrich=True, reactions={"counts": True})

# Update some parts of an activity with activity_partial_update
set = {
'product.name': 'boots',
'colors': {
'red': '0xFF0000',
'green': '0x00FF00'
}
}
unset = [ 'popularity', 'details.info' ]
# ...by ID
await client.activity_partial_update(id=activity_id, set=set, unset=unset)
# ...or by combination of foreign_id and time
await client.activity_partial_update(foreign_id=foreign_id, time=activity_time, set=set, unset=unset)

# Generating user token for client side usage (JS client)
user_token = client.create_user_token("user-42")

# Javascript client side feed initialization
# client = stream.connect(apiKey, userToken, appId);

# Generate a redirect url for the Stream Analytics platform to track
# events/impressions on url clicks
impression = {
'content_list': ['tweet:1', 'tweet:2', 'tweet:3'],
'user_data': 'tommaso',
'location': 'email',
'feed_id': 'user:global'
}

engagement = {
'content': 'tweet:2',
'label': 'click',
'position': 1,
'user_data': 'tommaso',
'location': 'email',
'feed_id':
'user:global'
}

events = [impression, engagement]

redirect_url = client.create_redirect_url('http://google.com/', 'user_id', events)

```

[JS client](http://github.com/getstream/stream-js).

## ✍️ Contributing
=======

We welcome code changes that improve this library or fix a problem, please make sure to follow all best practices and add tests if applicable before submitting a Pull Request on Github. We are very happy to merge your code in the official repository. Make sure to sign our [Contributor License Agreement (CLA)](https://docs.google.com/forms/d/e/1FAIpQLScFKsKkAJI7mhCr7K9rEIOpqIDThrWxuvxnwUq2XkHyG154vQ/viewform) first. See our [license file](./LICENSE) for more details.

Expand Down
3 changes: 2 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@
"requests>=2.3.0,<3",
"pyjwt>=2.0.0,<3",
"pytz>=2019.3",
"aiohttp>=3.6.0",
]
tests_require = ["pytest", "pytest-cov", "python-dateutil"]
tests_require = ["pytest", "pytest-cov", "python-dateutil", "pytest-asyncio"]
ci_require = ["black", "flake8", "pytest-cov"]

long_description = open("README.md", "r").read()
Expand Down
15 changes: 14 additions & 1 deletion stream/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ def connect(
timeout=3.0,
location=None,
base_url=None,
use_async=False,
):
"""
Returns a Client object

:param api_key: your api key or heroku url
:param api_secret: the api secret
:param app_id: the app id (used for listening to feed changes)
:param use_async: flag to set AsyncClient
"""
from stream.client import StreamClient
from stream.client import AsyncStreamClient, StreamClient

stream_url = os.environ.get("STREAM_URL")
# support for the heroku STREAM_URL syntax
Expand All @@ -42,6 +44,17 @@ def connect(
else:
raise ValueError("Invalid api key or heroku url")

if use_async:
return AsyncStreamClient(
api_key,
api_secret,
app_id,
version,
timeout,
location=location,
base_url=base_url,
)

return StreamClient(
api_key,
api_secret,
Expand Down
2 changes: 2 additions & 0 deletions stream/client/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
from .async_client import AsyncStreamClient
Comment thread
ferhatelmas marked this conversation as resolved.
from .client import StreamClient
Comment thread
ferhatelmas marked this conversation as resolved.
Loading