Skip to content

Commit e63f164

Browse files
committed
added sync and async fixed docs and readme
1 parent 38056bb commit e63f164

36 files changed

+3585
-2468
lines changed

.coverage

0 Bytes
Binary file not shown.

README.md

Lines changed: 566 additions & 694 deletions
Large diffs are not rendered by default.
27.6 KB
Binary file not shown.

dist/wasenderapi-0.2.0.tar.gz

73.9 KB
Binary file not shown.

docs/channel.md

Lines changed: 46 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -6,40 +6,26 @@ This document explains how to send messages to WhatsApp Channels using the Wasen
66

77
## Overview
88

9-
Sending a message to a WhatsApp Channel utilizes the existing generic `client.send()` method from the Wasender Python SDK. The key differences compared to sending a message to a regular user or group are:
9+
Sending a message to a WhatsApp Channel is straightforward with the Wasender Python SDK. You will typically use the `client.send_text()` helper method.
1010

11-
1. **Recipient (`to` field):** The `to` field in the message payload must be the unique **Channel ID** (also known as Channel JID). This typically looks like `12345678901234567890@newsletter`.
12-
2. **Message Type Restriction:** Currently, the Wasender API (and thus the SDK) generally **only supports sending text messages** to channels. Attempting to send other message types (images, videos, documents, etc.) to channels via the standard `send()` method may not be supported or could result in an API error. Always refer to the latest official Wasender API documentation for channel messaging capabilities.
11+
1. **Recipient (`to` field):** The `to` field in the `send_text()` method must be the unique **Channel ID** (also known as Channel JID). This typically looks like `12345678901234567890@newsletter`.
12+
2. **Message Type Restriction:** Currently, the Wasender API (and thus the SDK) generally **only supports sending text messages** to channels using the standard helper methods. Attempting to send other message types might not be supported. Always refer to the latest official Wasender API documentation for channel messaging capabilities.
1313

1414
## Prerequisites
1515

16-
1. **Obtain a Channel ID:** You need the specific ID of the channel you want to send a message to. One way to obtain a Channel ID is by listening for webhook events (e.g., `message.upsert` or `message.created` if your provider supports it for channels), as this event data for messages originating from a channel will include the channel's JID.
17-
2. **SDK Initialization:** Ensure the Wasender Python SDK is correctly initialized in your project. This involves:
16+
1. **Obtain a Channel ID:** You need the specific ID of the channel you want to send a message to.
17+
2. **SDK Initialization:** Ensure the Wasender Python SDK is correctly initialized.
1818
* Installing the SDK: `pip install wasenderapi`
19-
* Setting the environment variable `WASENDER_API_KEY`. This API key should correspond to the specific WhatsApp session you intend to use for sending channel messages.
20-
* Creating an instance of `WasenderClient`.
21-
(Refer to `README.md` or `docs/messages.md` for detailed SDK initialization examples.)
19+
* Setting the environment variable `WASENDER_API_KEY`.
20+
* Creating an instance of `WasenderAsyncClient` (or `WasenderSyncClient`).
2221

2322
## How to Send a Message to a Channel
2423

25-
You will use the `client.send()` method with a `TextPayload` Pydantic model. The Python SDK also provides a specific type alias `wasenderapi.models.channel.ChannelTextMessage` which is an alias for `TextPayload`, intended for conceptual clarity when working with channels.
26-
27-
### Python Model for Channel Messages
28-
29-
The relevant Pydantic model from `wasenderapi.models.channel` is:
30-
31-
```python
32-
# From wasenderapi/models/channel.py
33-
# (Conceptual - actual import would be from wasenderapi.models)
34-
from ..models.message import TextPayload # Relative import path for illustration
35-
36-
ChannelTextMessage = TextPayload
37-
```
38-
This means you can directly use `TextPayload` from `wasenderapi.models` when constructing your message for a channel.
24+
Use the `client.send_text()` method.
3925

4026
### Code Example
4127

42-
Here's how you can send a text message to a WhatsApp Channel in Python:
28+
Here's how you can send a text message to a WhatsApp Channel in Python using the async client:
4329

4430
```python
4531
# examples/send_channel_message.py
@@ -49,117 +35,89 @@ import logging
4935
from datetime import datetime
5036
from typing import Optional
5137

52-
from wasenderapi import WasenderClient
38+
# Corrected imports
39+
from wasenderapi import create_async_wasender, WasenderAsyncClient # For type hinting
5340
from wasenderapi.errors import WasenderAPIError
5441
from wasenderapi.models import (
55-
TextPayload, # Equivalent to ChannelTextMessage
56-
WasenderSendResult,
42+
WasenderSendResult, # Result from send_text
5743
RateLimitInfo
44+
# RetryConfig could be imported here if configuring retries
5845
)
5946

6047
# Configure basic logging
6148
logging.basicConfig(level=logging.INFO)
6249
logger = logging.getLogger(__name__)
6350

6451
# --- SDK Initialization (Minimal for this example) ---
65-
api_key = os.getenv("WASENDER_API_KEY") # API Key for the session sending the message
52+
api_key = os.getenv("WASENDER_API_KEY")
6653

6754
if not api_key:
68-
logger.error("Error: WASENDER_API_KEY environment variable is not set.")
69-
exit(1)
70-
71-
# For sending messages via an existing session, typically only the session's API key is needed.
72-
client = WasenderClient(api_key=api_key)
55+
logger.error("Error: WASENDER_API_KEY environment variable not set.")
56+
api_key = "YOUR_API_KEY_PLACEHOLDER" # Use a placeholder for docs
7357

74-
# The personal_access_token is generally used for account-level session management (create, list, delete sessions),
75-
# not for sending messages through an already established session.
76-
# # personal_access_token = os.getenv("WASENDER_PERSONAL_ACCESS_TOKEN") # Token for account-level session operations
77-
# # client = WasenderClient(api_key=api_key, personal_access_token=personal_access_token) # If needed for specific advanced scenarios or different auth models
58+
# Initialize async client
59+
async_client = create_async_wasender(api_key=api_key)
7860

7961
# --- Helper to log rate limits (can be imported from a common utils module) ---
80-
def log_rate_limit_info(rate_limit: Optional[RateLimitInfo]):
81-
if rate_limit:
82-
reset_time_str = datetime.fromtimestamp(rate_limit.reset_timestamp).strftime('%Y-%m-%d %H:%M:%S') if rate_limit.reset_timestamp else "N/A"
83-
logger.info(
84-
f"Rate Limit Info: Remaining = {rate_limit.remaining}, Limit = {rate_limit.limit}, Resets at = {reset_time_str}"
85-
)
86-
else:
87-
logger.info("Rate limit information not available for this request.")
88-
89-
# --- Generic Error Handler (can be imported) ---
90-
def handle_channel_api_error(error: Exception, operation: str, channel_jid: Optional[str] = None):
91-
target = f" for channel {channel_jid}" if channel_jid else ""
92-
if isinstance(error, WasenderAPIError):
93-
logger.error(f"API Error during {operation}{target}:")
94-
logger.error(f" Message: {error.message}")
95-
logger.error(f" Status Code: {error.status_code or 'N/A'}")
96-
if error.api_message: logger.error(f" API Message: {error.api_message}")
97-
if error.error_details: logger.error(f" Error Details: {error.error_details}")
98-
if error.rate_limit: log_rate_limit_info(error.rate_limit)
99-
else:
100-
logger.error(f"An unexpected error occurred during {operation}{target}: {error}")
62+
# (Assuming log_rate_limit_info and handle_channel_api_error are defined as in the original doc or a shared util)
10163

10264
# --- Main function to send message to channel ---
103-
async def send_message_to_channel_example(channel_jid: str, message_text: str):
104-
logger.info(f"\\n--- Attempting to Send Message to Channel: {channel_jid} ---")
65+
async def send_message_to_channel_example(client: WasenderAsyncClient, channel_jid: str, message_text: str):
66+
logger.info(f"\n--- Attempting to Send Message to Channel: {channel_jid} ---")
67+
if client.api_key == "YOUR_API_KEY_PLACEHOLDER":
68+
logger.warning(f"Skipping API call for send_message_to_channel {channel_jid}: API key is placeholder.")
69+
return
10570
if not channel_jid:
10671
logger.error("Channel JID is required.")
10772
return
10873
if not message_text:
10974
logger.error("Message text is required.")
11075
return
11176

112-
# Use TextPayload (aliased as ChannelTextMessage in the SDK for conceptual clarity)
113-
channel_payload = TextPayload(
114-
to=channel_jid,
115-
text=message_text,
116-
# messageType defaults to "text" in TextPayload model, so explicit set is optional
117-
# but good for clarity with channels: message_type="text"
118-
)
119-
12077
try:
121-
result = await client.send(payload=channel_payload)
122-
send_result: WasenderSendResult = result.response.data
78+
# Use the send_text helper method
79+
response: WasenderSendResult = await client.send_text(
80+
to=channel_jid,
81+
text_body=message_text
82+
)
12383

12484
logger.info(f"Message sent to channel {channel_jid} successfully.")
125-
logger.info(f" Message ID: {send_result.message_id}")
126-
logger.info(f" Status: {send_result.status}")
127-
if send_result.detail:
128-
logger.info(f" Detail: {send_result.detail}")
85+
if response.response and response.response.data:
86+
logger.info(f" Message ID: {response.response.data.message_id}")
87+
logger.info(f" Status: {response.response.message}")
12988

130-
log_rate_limit_info(result.rate_limit)
89+
# log_rate_limit_info(response.rate_limit) # Assuming log_rate_limit_info is defined
90+
if response.rate_limit:
91+
logger.info(f" Rate limit remaining: {response.rate_limit.remaining}")
13192

93+
except WasenderAPIError as e:
94+
# handle_channel_api_error(e, "sending message", channel_jid=channel_jid) # Assuming defined
95+
logger.error(f"API Error sending to channel {channel_jid}: {e.message}")
13296
except Exception as e:
133-
handle_channel_api_error(e, "sending message", channel_jid=channel_jid)
97+
logger.error(f"Unexpected error sending to channel {channel_jid}: {e}")
13498

13599
async def main():
136100
# Replace with the actual Channel ID you want to send a message to
137101
target_channel_jid = "12345678901234567890@newsletter" # Example JID
138102
message = "Hello Channel! This is a test message from the Python SDK."
139103

140-
if target_channel_jid == "12345678901234567890@newsletter":
141-
logger.warning("Please replace `target_channel_jid` with a real Channel ID before running.")
104+
if target_channel_jid == "12345678901234567890@newsletter" or async_client.api_key == "YOUR_API_KEY_PLACEHOLDER":
105+
logger.warning("Please replace `target_channel_jid` with a real Channel ID and ensure API key is set before running.")
142106
else:
143-
await send_message_to_channel_example(target_channel_jid, message)
107+
async with async_client: # Use async context manager for the client
108+
await send_message_to_channel_example(async_client, target_channel_jid, message)
144109

145-
# Example for another channel or message:
146-
# another_channel_jid = "09876543210987654321@newsletter"
147-
# await send_message_to_channel_example(another_channel_jid, "Another important update!")
148-
149110
if __name__ == "__main__":
150-
# Before running, ensure WASENDER_API_KEY is set in your environment.
151-
# Also, replace target_channel_jid in main() with a valid Channel ID.
152111
logger.info("Starting channel message example. Ensure JID and API Key are set.")
153112
asyncio.run(main())
154113

155114
```
156115

157116
### Key Points from the Example:
158117

159-
- **`to`**: Set to the `target_channel_jid`.
160-
- **`TextPayload`**: Used to construct the message. The `message_type` attribute within `TextPayload` defaults to `"text"`, which is what channels typically require. You can explicitly set `message_type="text"` for clarity if desired.
161-
- **`text`**: Contains the content of your message.
162-
- The example includes minimal SDK initialization, error handling, and rate limit logging.
118+
- **`create_async_wasender`**: Used to initialize the client.
119+
- **`client.send_text(to=channel_jid, text_body=message_text)`**: The recommended way to send text to a channel.
120+
- The example includes minimal SDK initialization and basic error logging.
163121

164122
## Important Considerations
165123

0 commit comments

Comments
 (0)