|
3 | 3 | from datetime import date, datetime |
4 | 4 | from typing import Any, Dict, List, Optional, Union |
5 | 5 |
|
| 6 | +from ._subscriptions_common import ( |
| 7 | + build_attribution_headers, |
| 8 | + build_create_body, |
| 9 | + unwrap_data, |
| 10 | +) |
6 | 11 | from .exceptions import ValidationError |
7 | | -from .models import DieselPrice, DieselStationsResponse, PriceAlert |
| 12 | +from .models import DieselPrice, DieselStationsResponse, PriceAlert, Subscription, SubscriptionEvent |
8 | 13 | from .resource_validators import VALID_OPERATORS, format_date |
9 | 14 | from .resources._futures_slug import normalize_futures_slug |
| 15 | +from .resources.subscriptions import SubscriptionEventsPage |
10 | 16 |
|
11 | 17 |
|
12 | 18 | class AsyncDieselResource: |
@@ -1403,3 +1409,83 @@ async def rotate_credentials(self, source_id: str, new_credentials: Dict[str, An |
1403 | 1409 | if "data" in response: |
1404 | 1410 | return response["data"] |
1405 | 1411 | return response |
| 1412 | + |
| 1413 | + |
| 1414 | +class AsyncSubscriptionsResource: |
| 1415 | + """Async resource for agent-subscription CRUD and event polling (#3245).""" |
| 1416 | + |
| 1417 | + def __init__(self, client: Any) -> None: |
| 1418 | + self.client = client |
| 1419 | + |
| 1420 | + async def list(self) -> List[Subscription]: |
| 1421 | + """List all subscriptions for the authenticated user.""" |
| 1422 | + response = await self.client.request(method="GET", path="/v1/subscriptions") |
| 1423 | + data = unwrap_data(response) |
| 1424 | + subs = data.get("subscriptions", []) |
| 1425 | + return [Subscription(**s) for s in subs] |
| 1426 | + |
| 1427 | + async def create( |
| 1428 | + self, |
| 1429 | + codes: List[str], |
| 1430 | + interval: Union[str, int], |
| 1431 | + name: Optional[str] = None, |
| 1432 | + source: Optional[str] = None, |
| 1433 | + tool: Optional[str] = None, |
| 1434 | + ) -> Subscription: |
| 1435 | + """Create a new subscription (watch). |
| 1436 | +
|
| 1437 | + Args: |
| 1438 | + codes: Commodity codes to watch (e.g. ["BRENT_CRUDE_USD"]). |
| 1439 | + interval: Friendly interval ("5m", "1h", "daily") or seconds (int). |
| 1440 | + name: Optional human-friendly name. |
| 1441 | + source: Attribution source header (defaults to "sdk-python"). |
| 1442 | + tool: Optional attribution tool name header. |
| 1443 | + """ |
| 1444 | + body = build_create_body(codes, interval, name=name) |
| 1445 | + headers = build_attribution_headers(source=source, tool=tool) |
| 1446 | + response = await self.client.request( |
| 1447 | + method="POST", |
| 1448 | + path="/v1/subscriptions", |
| 1449 | + json_data=body, |
| 1450 | + headers=headers, |
| 1451 | + ) |
| 1452 | + data = unwrap_data(response) |
| 1453 | + sub = data.get("subscription", data) |
| 1454 | + return Subscription(**sub) |
| 1455 | + |
| 1456 | + async def delete(self, subscription_id: str) -> bool: |
| 1457 | + """Delete a subscription. Returns True on success.""" |
| 1458 | + await self.client.request( |
| 1459 | + method="DELETE", |
| 1460 | + path=f"/v1/subscriptions/{subscription_id}", |
| 1461 | + ) |
| 1462 | + return True |
| 1463 | + |
| 1464 | + async def events( |
| 1465 | + self, |
| 1466 | + since: Optional[int] = None, |
| 1467 | + limit: Optional[int] = None, |
| 1468 | + watch_id: Optional[str] = None, |
| 1469 | + ) -> SubscriptionEventsPage: |
| 1470 | + """Poll for subscription events newer than a cursor. |
| 1471 | +
|
| 1472 | + Returns a SubscriptionEventsPage with events, cursor, and has_more. |
| 1473 | + """ |
| 1474 | + params: Dict[str, Any] = {} |
| 1475 | + if since is not None: |
| 1476 | + params["since"] = since |
| 1477 | + if limit is not None: |
| 1478 | + params["limit"] = limit |
| 1479 | + if watch_id is not None: |
| 1480 | + params["watch_id"] = watch_id |
| 1481 | + |
| 1482 | + response = await self.client.request( |
| 1483 | + method="GET", |
| 1484 | + path="/v1/subscriptions/events", |
| 1485 | + params=params, |
| 1486 | + ) |
| 1487 | + data = unwrap_data(response) |
| 1488 | + events = [SubscriptionEvent(**e) for e in data.get("events", [])] |
| 1489 | + cursor = data.get("cursor") |
| 1490 | + has_more = bool(data.get("has_more", False)) |
| 1491 | + return SubscriptionEventsPage(events=events, cursor=cursor, has_more=has_more) |
0 commit comments