mailerbot 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- mailerbot/__init__.py +50 -0
- mailerbot/_http.py +53 -0
- mailerbot/_pagination.py +43 -0
- mailerbot/async_client.py +604 -0
- mailerbot/client.py +64 -0
- mailerbot/exceptions.py +30 -0
- mailerbot/models/__init__.py +28 -0
- mailerbot/models/assets.py +13 -0
- mailerbot/models/auth.py +62 -0
- mailerbot/models/campaigns.py +12 -0
- mailerbot/models/common.py +22 -0
- mailerbot/models/contacts.py +43 -0
- mailerbot/models/coupons.py +38 -0
- mailerbot/models/dashboard.py +25 -0
- mailerbot/models/documents.py +16 -0
- mailerbot/models/mailings.py +102 -0
- mailerbot/models/merge_tags.py +9 -0
- mailerbot/models/oauth.py +28 -0
- mailerbot/models/payments.py +20 -0
- mailerbot/models/postcards.py +32 -0
- mailerbot/models/qr.py +37 -0
- mailerbot/resources/__init__.py +0 -0
- mailerbot/resources/assets.py +40 -0
- mailerbot/resources/auth.py +58 -0
- mailerbot/resources/campaigns.py +62 -0
- mailerbot/resources/contact_lists.py +53 -0
- mailerbot/resources/contacts.py +97 -0
- mailerbot/resources/coupons.py +73 -0
- mailerbot/resources/dashboard.py +26 -0
- mailerbot/resources/documents.py +62 -0
- mailerbot/resources/mailings.py +145 -0
- mailerbot/resources/merge_tags.py +16 -0
- mailerbot/resources/oauth.py +38 -0
- mailerbot/resources/payments.py +33 -0
- mailerbot/resources/postcards.py +57 -0
- mailerbot/resources/pricing.py +35 -0
- mailerbot/resources/qr.py +54 -0
- mailerbot-0.1.0.dist-info/METADATA +343 -0
- mailerbot-0.1.0.dist-info/RECORD +40 -0
- mailerbot-0.1.0.dist-info/WHEEL +4 -0
mailerbot/__init__.py
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
from .client import MailerBot
|
|
2
|
+
from .async_client import AsyncMailerBot
|
|
3
|
+
from .exceptions import (
|
|
4
|
+
MailerBotError,
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
PermissionError,
|
|
7
|
+
NotFoundError,
|
|
8
|
+
ValidationError,
|
|
9
|
+
RateLimitError,
|
|
10
|
+
ServerError,
|
|
11
|
+
)
|
|
12
|
+
from .models import (
|
|
13
|
+
Page,
|
|
14
|
+
Contact, ContactList, AddressValidation, CsvImportResult,
|
|
15
|
+
Document,
|
|
16
|
+
Postcard, PostcardTemplate,
|
|
17
|
+
Mailing, CostCalculation, MailingItemTracking, MailingItemScan,
|
|
18
|
+
Campaign,
|
|
19
|
+
DashboardStats, ReportingData,
|
|
20
|
+
PaymentIntent, SavedCard,
|
|
21
|
+
QrLink, QrAnalytics,
|
|
22
|
+
CouponList, CouponCode, CouponImportResult, CouponAvailability,
|
|
23
|
+
Asset,
|
|
24
|
+
MergeTag,
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
__version__ = "0.1.0"
|
|
28
|
+
__all__ = [
|
|
29
|
+
"MailerBot",
|
|
30
|
+
"AsyncMailerBot",
|
|
31
|
+
"MailerBotError",
|
|
32
|
+
"AuthenticationError",
|
|
33
|
+
"PermissionError",
|
|
34
|
+
"NotFoundError",
|
|
35
|
+
"ValidationError",
|
|
36
|
+
"RateLimitError",
|
|
37
|
+
"ServerError",
|
|
38
|
+
"Page",
|
|
39
|
+
"Contact", "ContactList", "AddressValidation", "CsvImportResult",
|
|
40
|
+
"Document",
|
|
41
|
+
"Postcard", "PostcardTemplate",
|
|
42
|
+
"Mailing", "CostCalculation", "MailingItemTracking", "MailingItemScan",
|
|
43
|
+
"Campaign",
|
|
44
|
+
"DashboardStats", "ReportingData",
|
|
45
|
+
"PaymentIntent", "SavedCard",
|
|
46
|
+
"QrLink", "QrAnalytics",
|
|
47
|
+
"CouponList", "CouponCode", "CouponImportResult", "CouponAvailability",
|
|
48
|
+
"Asset",
|
|
49
|
+
"MergeTag",
|
|
50
|
+
]
|
mailerbot/_http.py
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
import httpx
|
|
3
|
+
from .exceptions import (
|
|
4
|
+
MailerBotError, AuthenticationError, PermissionError,
|
|
5
|
+
NotFoundError, ValidationError, RateLimitError, ServerError,
|
|
6
|
+
)
|
|
7
|
+
|
|
8
|
+
DEFAULT_BASE_URL = "https://api.mailerbot.com/api/v1"
|
|
9
|
+
DEFAULT_TIMEOUT = 30.0
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _raise_for_status(response: httpx.Response) -> None:
|
|
13
|
+
if response.is_success:
|
|
14
|
+
return
|
|
15
|
+
try:
|
|
16
|
+
body = response.json()
|
|
17
|
+
except Exception:
|
|
18
|
+
body = {"detail": response.text}
|
|
19
|
+
|
|
20
|
+
detail = body.get("detail", str(body))
|
|
21
|
+
status = response.status_code
|
|
22
|
+
|
|
23
|
+
if status == 401:
|
|
24
|
+
raise AuthenticationError(detail, status_code=status, response=body)
|
|
25
|
+
if status == 403:
|
|
26
|
+
raise PermissionError(detail, status_code=status, response=body)
|
|
27
|
+
if status == 404:
|
|
28
|
+
raise NotFoundError(detail, status_code=status, response=body)
|
|
29
|
+
if status == 422:
|
|
30
|
+
raise ValidationError(detail, status_code=status, response=body)
|
|
31
|
+
if status == 429:
|
|
32
|
+
raise RateLimitError(detail, status_code=status, response=body)
|
|
33
|
+
if status >= 500:
|
|
34
|
+
raise ServerError(detail, status_code=status, response=body)
|
|
35
|
+
raise MailerBotError(detail, status_code=status, response=body)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def _build_headers(
|
|
39
|
+
*,
|
|
40
|
+
api_key: str | None = None,
|
|
41
|
+
bearer_token: str | None = None,
|
|
42
|
+
) -> dict[str, str]:
|
|
43
|
+
headers: dict[str, str] = {
|
|
44
|
+
"Content-Type": "application/json",
|
|
45
|
+
"Accept": "application/json",
|
|
46
|
+
}
|
|
47
|
+
if api_key:
|
|
48
|
+
headers["X-API-Key"] = api_key
|
|
49
|
+
elif bearer_token:
|
|
50
|
+
headers["Authorization"] = f"Bearer {bearer_token}"
|
|
51
|
+
else:
|
|
52
|
+
raise ValueError("Either api_key or bearer_token must be provided")
|
|
53
|
+
return headers
|
mailerbot/_pagination.py
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
from typing import Generic, TypeVar, Callable, Iterator, AsyncIterator
|
|
3
|
+
from .models.common import Page
|
|
4
|
+
|
|
5
|
+
T = TypeVar("T")
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class PageIterator(Generic[T]):
|
|
9
|
+
"""Sync auto-paginating iterator. Yields individual items across all pages."""
|
|
10
|
+
|
|
11
|
+
def __init__(self, fetch: Callable[[int, int], Page[T]], page_size: int = 100):
|
|
12
|
+
self._fetch = fetch
|
|
13
|
+
self._page_size = page_size
|
|
14
|
+
|
|
15
|
+
def __iter__(self) -> Iterator[T]:
|
|
16
|
+
page = 1
|
|
17
|
+
while True:
|
|
18
|
+
result = self._fetch(page, self._page_size)
|
|
19
|
+
yield from result.items
|
|
20
|
+
if page >= result.pages:
|
|
21
|
+
break
|
|
22
|
+
page += 1
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class AsyncPageIterator(Generic[T]):
|
|
26
|
+
"""Async auto-paginating iterator. Yields individual items across all pages."""
|
|
27
|
+
|
|
28
|
+
def __init__(self, fetch: Callable[[int, int], object], page_size: int = 100):
|
|
29
|
+
self._fetch = fetch
|
|
30
|
+
self._page_size = page_size
|
|
31
|
+
|
|
32
|
+
def __aiter__(self) -> AsyncIterator[T]:
|
|
33
|
+
return self._iterate()
|
|
34
|
+
|
|
35
|
+
async def _iterate(self) -> AsyncIterator[T]:
|
|
36
|
+
page = 1
|
|
37
|
+
while True:
|
|
38
|
+
result = await self._fetch(page, self._page_size)
|
|
39
|
+
for item in result.items:
|
|
40
|
+
yield item
|
|
41
|
+
if page >= result.pages:
|
|
42
|
+
break
|
|
43
|
+
page += 1
|