keplars 1.0.0__tar.gz
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.
- keplars-1.0.0/PKG-INFO +222 -0
- keplars-1.0.0/README.md +193 -0
- keplars-1.0.0/pyproject.toml +72 -0
- keplars-1.0.0/src/keplars/__init__.py +74 -0
- keplars-1.0.0/src/keplars/audiences.py +90 -0
- keplars-1.0.0/src/keplars/automations.py +92 -0
- keplars-1.0.0/src/keplars/client.py +294 -0
- keplars-1.0.0/src/keplars/contacts.py +112 -0
- keplars-1.0.0/src/keplars/domains.py +84 -0
- keplars-1.0.0/src/keplars/errors.py +97 -0
- keplars-1.0.0/src/keplars/models.py +156 -0
- keplars-1.0.0/src/keplars/resources.py +107 -0
- keplars-1.0.0/src/keplars/utils.py +48 -0
keplars-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: keplars
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Official Python SDK for Keplars Email API - modern transactional email service with priority-based delivery
|
|
5
|
+
Home-page: https://keplars.com
|
|
6
|
+
License: MIT
|
|
7
|
+
Keywords: keplars,email,transactional,api,sdk,priority,scheduling
|
|
8
|
+
Author: Keplars
|
|
9
|
+
Author-email: support@keplars.com
|
|
10
|
+
Requires-Python: >=3.8,<4.0
|
|
11
|
+
Classifier: Development Status :: 4 - Beta
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
21
|
+
Classifier: Topic :: Communications :: Email
|
|
22
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
23
|
+
Requires-Dist: httpx (>=0.26.0,<0.27.0)
|
|
24
|
+
Requires-Dist: pydantic[email] (>=2.5.0,<3.0.0)
|
|
25
|
+
Project-URL: Documentation, https://docs.keplars.com
|
|
26
|
+
Project-URL: Repository, https://github.com/Swing-Technologies/keplers-mail-sdk
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# Keplars Email SDK for Python
|
|
30
|
+
|
|
31
|
+
Official Python SDK for the Keplars Email API - modern transactional email service with priority-based delivery.
|
|
32
|
+
|
|
33
|
+
## Installation
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install keplars
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
or with Poetry:
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
poetry add keplars
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Quick Start
|
|
46
|
+
|
|
47
|
+
### Synchronous Client
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from keplars import Keplars
|
|
51
|
+
|
|
52
|
+
client = Keplars(api_key='kms_<workspaceId>.live_<secret>')
|
|
53
|
+
|
|
54
|
+
result = client.emails.send_instant(
|
|
55
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
56
|
+
to='user@example.com',
|
|
57
|
+
subject='Your verification code is 123456',
|
|
58
|
+
html='<p>Your verification code is <strong>123456</strong></p>'
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
print(result.data.job_id)
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Async Client
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
import asyncio
|
|
68
|
+
from keplars import AsyncKeplars
|
|
69
|
+
|
|
70
|
+
async def main():
|
|
71
|
+
async with AsyncKeplars(api_key='kms_<workspaceId>.live_<secret>') as client:
|
|
72
|
+
result = await client.emails.send_instant(
|
|
73
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
74
|
+
to='user@example.com',
|
|
75
|
+
subject='Welcome!',
|
|
76
|
+
html='<h1>Welcome aboard</h1>'
|
|
77
|
+
)
|
|
78
|
+
print(result.data.job_id)
|
|
79
|
+
|
|
80
|
+
asyncio.run(main())
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### API Key Types
|
|
84
|
+
|
|
85
|
+
| Type | Format | Used for |
|
|
86
|
+
|---|---|---|
|
|
87
|
+
| Regular | `kms_<id>.live_<secret>` | Email sending |
|
|
88
|
+
| Admin | `kms_<id>.adm_<secret>` | Contacts, audiences, automations, domains |
|
|
89
|
+
|
|
90
|
+
## Email Sending
|
|
91
|
+
|
|
92
|
+
### Priority Levels
|
|
93
|
+
|
|
94
|
+
| Method | Delivery | Use case |
|
|
95
|
+
|---|---|---|
|
|
96
|
+
| `send_instant` | 0–5 sec | OTPs, login codes, critical alerts |
|
|
97
|
+
| `send_high` | 0–30 sec | Transactional, notifications |
|
|
98
|
+
| `send_async` / `send` | 0–5 min | General transactional |
|
|
99
|
+
| `send_bulk` | Idle | Newsletters, marketing |
|
|
100
|
+
|
|
101
|
+
### Response Shape
|
|
102
|
+
|
|
103
|
+
```python
|
|
104
|
+
result.success # True
|
|
105
|
+
result.message # 'Email queued'
|
|
106
|
+
result.data.job_id # 'job_abc123'
|
|
107
|
+
result.data.priority # 'instant'
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### Send with Recipients
|
|
111
|
+
|
|
112
|
+
```python
|
|
113
|
+
result = client.emails.send_high(
|
|
114
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
115
|
+
to=[{'email': 'user@example.com', 'name': 'John Doe'}],
|
|
116
|
+
cc=[{'email': 'manager@example.com'}],
|
|
117
|
+
subject='Order Confirmation',
|
|
118
|
+
html='<p>Your order has been confirmed</p>'
|
|
119
|
+
)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Send with Template
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
result = client.emails.send(
|
|
126
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
127
|
+
to='user@example.com',
|
|
128
|
+
subject='Password Reset',
|
|
129
|
+
template_id='tpl_reset_password',
|
|
130
|
+
template_data={'name': 'John', 'reset_link': 'https://example.com/reset/abc'}
|
|
131
|
+
)
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
### Schedule Email
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
result = client.emails.schedule(
|
|
138
|
+
**{'from': 'newsletter@yourdomain.com'},
|
|
139
|
+
to='user@example.com',
|
|
140
|
+
subject='Your weekly digest',
|
|
141
|
+
html='<p>Here is your weekly digest...</p>',
|
|
142
|
+
scheduled_for='2026-06-01T09:00:00Z',
|
|
143
|
+
priority='bulk'
|
|
144
|
+
)
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Contacts (Admin API Key Required)
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
admin_client = Keplars(api_key='kms_<workspaceId>.adm_<secret>')
|
|
151
|
+
|
|
152
|
+
admin_client.contacts.add(email='user@example.com', name='John Doe', audience_id='aud_abc123')
|
|
153
|
+
|
|
154
|
+
contact = admin_client.contacts.get('user@example.com')
|
|
155
|
+
|
|
156
|
+
contacts = admin_client.contacts.list(audience_id='aud_abc123', page=1, limit=20)
|
|
157
|
+
|
|
158
|
+
admin_client.contacts.update('user@example.com', name='Jane Doe')
|
|
159
|
+
|
|
160
|
+
admin_client.contacts.delete('user@example.com')
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
## Audiences (Admin API Key Required)
|
|
164
|
+
|
|
165
|
+
```python
|
|
166
|
+
audience = admin_client.audiences.create('Newsletter Subscribers', description='Main list')
|
|
167
|
+
|
|
168
|
+
audiences = admin_client.audiences.list(page=1, limit=20)
|
|
169
|
+
|
|
170
|
+
audience = admin_client.audiences.get('aud_abc123')
|
|
171
|
+
|
|
172
|
+
admin_client.audiences.delete('aud_abc123')
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Automations (Admin API Key Required)
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
automations = admin_client.automations.list()
|
|
179
|
+
|
|
180
|
+
automation = admin_client.automations.get('auto_abc123')
|
|
181
|
+
|
|
182
|
+
admin_client.automations.enroll('auto_abc123', 'user@example.com')
|
|
183
|
+
|
|
184
|
+
admin_client.automations.unenroll('auto_abc123', 'user@example.com')
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Domains (Admin API Key Required)
|
|
188
|
+
|
|
189
|
+
```python
|
|
190
|
+
domain = admin_client.domains.add('mail.yourcompany.com')
|
|
191
|
+
|
|
192
|
+
domains = admin_client.domains.list()
|
|
193
|
+
|
|
194
|
+
status = admin_client.domains.get_status('dom_abc123')
|
|
195
|
+
|
|
196
|
+
result = admin_client.domains.verify('dom_abc123')
|
|
197
|
+
|
|
198
|
+
api_key = admin_client.domains.create_api_key(domain_id='dom_abc123', name='Production Key')
|
|
199
|
+
|
|
200
|
+
admin_client.domains.delete('dom_abc123')
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
## Error Handling
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
from keplars import (
|
|
207
|
+
Keplars,
|
|
208
|
+
AuthenticationError,
|
|
209
|
+
RateLimitError,
|
|
210
|
+
ValidationError,
|
|
211
|
+
)
|
|
212
|
+
|
|
213
|
+
try:
|
|
214
|
+
result = client.emails.send_instant(...)
|
|
215
|
+
except AuthenticationError:
|
|
216
|
+
print('Invalid API key')
|
|
217
|
+
except RateLimitError as e:
|
|
218
|
+
print(f'Rate limited, retry after: {e.retry_after}s')
|
|
219
|
+
except ValidationError as e:
|
|
220
|
+
print(f'Validation error: {e}')
|
|
221
|
+
```
|
|
222
|
+
|
keplars-1.0.0/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# Keplars Email SDK for Python
|
|
2
|
+
|
|
3
|
+
Official Python SDK for the Keplars Email API - modern transactional email service with priority-based delivery.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pip install keplars
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or with Poetry:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
poetry add keplars
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### Synchronous Client
|
|
20
|
+
|
|
21
|
+
```python
|
|
22
|
+
from keplars import Keplars
|
|
23
|
+
|
|
24
|
+
client = Keplars(api_key='kms_<workspaceId>.live_<secret>')
|
|
25
|
+
|
|
26
|
+
result = client.emails.send_instant(
|
|
27
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
28
|
+
to='user@example.com',
|
|
29
|
+
subject='Your verification code is 123456',
|
|
30
|
+
html='<p>Your verification code is <strong>123456</strong></p>'
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
print(result.data.job_id)
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
### Async Client
|
|
37
|
+
|
|
38
|
+
```python
|
|
39
|
+
import asyncio
|
|
40
|
+
from keplars import AsyncKeplars
|
|
41
|
+
|
|
42
|
+
async def main():
|
|
43
|
+
async with AsyncKeplars(api_key='kms_<workspaceId>.live_<secret>') as client:
|
|
44
|
+
result = await client.emails.send_instant(
|
|
45
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
46
|
+
to='user@example.com',
|
|
47
|
+
subject='Welcome!',
|
|
48
|
+
html='<h1>Welcome aboard</h1>'
|
|
49
|
+
)
|
|
50
|
+
print(result.data.job_id)
|
|
51
|
+
|
|
52
|
+
asyncio.run(main())
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### API Key Types
|
|
56
|
+
|
|
57
|
+
| Type | Format | Used for |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| Regular | `kms_<id>.live_<secret>` | Email sending |
|
|
60
|
+
| Admin | `kms_<id>.adm_<secret>` | Contacts, audiences, automations, domains |
|
|
61
|
+
|
|
62
|
+
## Email Sending
|
|
63
|
+
|
|
64
|
+
### Priority Levels
|
|
65
|
+
|
|
66
|
+
| Method | Delivery | Use case |
|
|
67
|
+
|---|---|---|
|
|
68
|
+
| `send_instant` | 0–5 sec | OTPs, login codes, critical alerts |
|
|
69
|
+
| `send_high` | 0–30 sec | Transactional, notifications |
|
|
70
|
+
| `send_async` / `send` | 0–5 min | General transactional |
|
|
71
|
+
| `send_bulk` | Idle | Newsletters, marketing |
|
|
72
|
+
|
|
73
|
+
### Response Shape
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
result.success # True
|
|
77
|
+
result.message # 'Email queued'
|
|
78
|
+
result.data.job_id # 'job_abc123'
|
|
79
|
+
result.data.priority # 'instant'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### Send with Recipients
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
result = client.emails.send_high(
|
|
86
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
87
|
+
to=[{'email': 'user@example.com', 'name': 'John Doe'}],
|
|
88
|
+
cc=[{'email': 'manager@example.com'}],
|
|
89
|
+
subject='Order Confirmation',
|
|
90
|
+
html='<p>Your order has been confirmed</p>'
|
|
91
|
+
)
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Send with Template
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
result = client.emails.send(
|
|
98
|
+
**{'from': 'noreply@yourdomain.com'},
|
|
99
|
+
to='user@example.com',
|
|
100
|
+
subject='Password Reset',
|
|
101
|
+
template_id='tpl_reset_password',
|
|
102
|
+
template_data={'name': 'John', 'reset_link': 'https://example.com/reset/abc'}
|
|
103
|
+
)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Schedule Email
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
result = client.emails.schedule(
|
|
110
|
+
**{'from': 'newsletter@yourdomain.com'},
|
|
111
|
+
to='user@example.com',
|
|
112
|
+
subject='Your weekly digest',
|
|
113
|
+
html='<p>Here is your weekly digest...</p>',
|
|
114
|
+
scheduled_for='2026-06-01T09:00:00Z',
|
|
115
|
+
priority='bulk'
|
|
116
|
+
)
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
## Contacts (Admin API Key Required)
|
|
120
|
+
|
|
121
|
+
```python
|
|
122
|
+
admin_client = Keplars(api_key='kms_<workspaceId>.adm_<secret>')
|
|
123
|
+
|
|
124
|
+
admin_client.contacts.add(email='user@example.com', name='John Doe', audience_id='aud_abc123')
|
|
125
|
+
|
|
126
|
+
contact = admin_client.contacts.get('user@example.com')
|
|
127
|
+
|
|
128
|
+
contacts = admin_client.contacts.list(audience_id='aud_abc123', page=1, limit=20)
|
|
129
|
+
|
|
130
|
+
admin_client.contacts.update('user@example.com', name='Jane Doe')
|
|
131
|
+
|
|
132
|
+
admin_client.contacts.delete('user@example.com')
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
## Audiences (Admin API Key Required)
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
audience = admin_client.audiences.create('Newsletter Subscribers', description='Main list')
|
|
139
|
+
|
|
140
|
+
audiences = admin_client.audiences.list(page=1, limit=20)
|
|
141
|
+
|
|
142
|
+
audience = admin_client.audiences.get('aud_abc123')
|
|
143
|
+
|
|
144
|
+
admin_client.audiences.delete('aud_abc123')
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## Automations (Admin API Key Required)
|
|
148
|
+
|
|
149
|
+
```python
|
|
150
|
+
automations = admin_client.automations.list()
|
|
151
|
+
|
|
152
|
+
automation = admin_client.automations.get('auto_abc123')
|
|
153
|
+
|
|
154
|
+
admin_client.automations.enroll('auto_abc123', 'user@example.com')
|
|
155
|
+
|
|
156
|
+
admin_client.automations.unenroll('auto_abc123', 'user@example.com')
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
## Domains (Admin API Key Required)
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
domain = admin_client.domains.add('mail.yourcompany.com')
|
|
163
|
+
|
|
164
|
+
domains = admin_client.domains.list()
|
|
165
|
+
|
|
166
|
+
status = admin_client.domains.get_status('dom_abc123')
|
|
167
|
+
|
|
168
|
+
result = admin_client.domains.verify('dom_abc123')
|
|
169
|
+
|
|
170
|
+
api_key = admin_client.domains.create_api_key(domain_id='dom_abc123', name='Production Key')
|
|
171
|
+
|
|
172
|
+
admin_client.domains.delete('dom_abc123')
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
## Error Handling
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
from keplars import (
|
|
179
|
+
Keplars,
|
|
180
|
+
AuthenticationError,
|
|
181
|
+
RateLimitError,
|
|
182
|
+
ValidationError,
|
|
183
|
+
)
|
|
184
|
+
|
|
185
|
+
try:
|
|
186
|
+
result = client.emails.send_instant(...)
|
|
187
|
+
except AuthenticationError:
|
|
188
|
+
print('Invalid API key')
|
|
189
|
+
except RateLimitError as e:
|
|
190
|
+
print(f'Rate limited, retry after: {e.retry_after}s')
|
|
191
|
+
except ValidationError as e:
|
|
192
|
+
print(f'Validation error: {e}')
|
|
193
|
+
```
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
[tool.poetry]
|
|
2
|
+
name = "keplars"
|
|
3
|
+
version = "1.0.0"
|
|
4
|
+
description = "Official Python SDK for Keplars Email API - modern transactional email service with priority-based delivery"
|
|
5
|
+
authors = ["Keplars <support@keplars.com>"]
|
|
6
|
+
license = "MIT"
|
|
7
|
+
readme = "README.md"
|
|
8
|
+
homepage = "https://keplars.com"
|
|
9
|
+
repository = "https://github.com/Swing-Technologies/keplers-mail-sdk"
|
|
10
|
+
documentation = "https://docs.keplars.com"
|
|
11
|
+
keywords = ["keplars", "email", "transactional", "api", "sdk", "priority", "scheduling"]
|
|
12
|
+
classifiers = [
|
|
13
|
+
"Development Status :: 4 - Beta",
|
|
14
|
+
"Intended Audience :: Developers",
|
|
15
|
+
"License :: OSI Approved :: MIT License",
|
|
16
|
+
"Programming Language :: Python :: 3",
|
|
17
|
+
"Programming Language :: Python :: 3.8",
|
|
18
|
+
"Programming Language :: Python :: 3.9",
|
|
19
|
+
"Programming Language :: Python :: 3.10",
|
|
20
|
+
"Programming Language :: Python :: 3.11",
|
|
21
|
+
"Programming Language :: Python :: 3.12",
|
|
22
|
+
"Topic :: Communications :: Email",
|
|
23
|
+
"Topic :: Software Development :: Libraries :: Python Modules",
|
|
24
|
+
]
|
|
25
|
+
packages = [{include = "keplars", from = "src"}]
|
|
26
|
+
|
|
27
|
+
[tool.poetry.dependencies]
|
|
28
|
+
python = "^3.8"
|
|
29
|
+
httpx = "^0.26.0"
|
|
30
|
+
pydantic = {version = "^2.5.0", extras = ["email"]}
|
|
31
|
+
|
|
32
|
+
[tool.poetry.group.dev.dependencies]
|
|
33
|
+
pytest = "^7.4.3"
|
|
34
|
+
pytest-asyncio = "^0.23.2"
|
|
35
|
+
pytest-cov = "^4.1.0"
|
|
36
|
+
pytest-mock = "^3.12.0"
|
|
37
|
+
black = "^23.12.1"
|
|
38
|
+
isort = "^5.13.2"
|
|
39
|
+
mypy = "^1.8.0"
|
|
40
|
+
ruff = "^0.1.9"
|
|
41
|
+
|
|
42
|
+
[build-system]
|
|
43
|
+
requires = ["poetry-core"]
|
|
44
|
+
build-backend = "poetry.core.masonry.api"
|
|
45
|
+
|
|
46
|
+
[tool.black]
|
|
47
|
+
line-length = 100
|
|
48
|
+
target-version = ['py38']
|
|
49
|
+
include = '\.pyi?$'
|
|
50
|
+
|
|
51
|
+
[tool.isort]
|
|
52
|
+
profile = "black"
|
|
53
|
+
line_length = 100
|
|
54
|
+
|
|
55
|
+
[tool.mypy]
|
|
56
|
+
python_version = "3.8"
|
|
57
|
+
strict = true
|
|
58
|
+
warn_return_any = true
|
|
59
|
+
warn_unused_configs = true
|
|
60
|
+
disallow_untyped_defs = true
|
|
61
|
+
|
|
62
|
+
[tool.ruff]
|
|
63
|
+
line-length = 100
|
|
64
|
+
target-version = "py38"
|
|
65
|
+
|
|
66
|
+
[tool.pytest.ini_options]
|
|
67
|
+
testpaths = ["tests"]
|
|
68
|
+
python_files = "test_*.py"
|
|
69
|
+
python_classes = "Test*"
|
|
70
|
+
python_functions = "test_*"
|
|
71
|
+
addopts = "-v --cov=keplars --cov-report=term-missing"
|
|
72
|
+
asyncio_mode = "auto"
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from .client import Keplars, AsyncKeplars
|
|
2
|
+
from .errors import (
|
|
3
|
+
KeplarsError,
|
|
4
|
+
ValidationError,
|
|
5
|
+
AuthenticationError,
|
|
6
|
+
AuthorizationError,
|
|
7
|
+
ConflictError,
|
|
8
|
+
DomainNotVerifiedError,
|
|
9
|
+
InternalError,
|
|
10
|
+
NetworkError,
|
|
11
|
+
NotFoundError,
|
|
12
|
+
PlanLimitError,
|
|
13
|
+
QuotaExceededError,
|
|
14
|
+
RateLimitError,
|
|
15
|
+
)
|
|
16
|
+
from .models import (
|
|
17
|
+
EmailPriority,
|
|
18
|
+
ErrorCode,
|
|
19
|
+
KeplarsConfig,
|
|
20
|
+
EmailRecipient,
|
|
21
|
+
SendEmailRequest,
|
|
22
|
+
SendEmailResponse,
|
|
23
|
+
SendEmailData,
|
|
24
|
+
ScheduleEmailRequest,
|
|
25
|
+
ScheduledEmailResponse,
|
|
26
|
+
Contact,
|
|
27
|
+
Audience,
|
|
28
|
+
Automation,
|
|
29
|
+
DomainListItem,
|
|
30
|
+
PaginatedMeta,
|
|
31
|
+
ErrorDetail,
|
|
32
|
+
RateLimitInfo,
|
|
33
|
+
)
|
|
34
|
+
from .utils import (
|
|
35
|
+
verify_webhook_signature,
|
|
36
|
+
render_template,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
__version__ = "1.0.0"
|
|
40
|
+
|
|
41
|
+
__all__ = [
|
|
42
|
+
"Keplars",
|
|
43
|
+
"AsyncKeplars",
|
|
44
|
+
"KeplarsError",
|
|
45
|
+
"ValidationError",
|
|
46
|
+
"AuthenticationError",
|
|
47
|
+
"AuthorizationError",
|
|
48
|
+
"ConflictError",
|
|
49
|
+
"DomainNotVerifiedError",
|
|
50
|
+
"InternalError",
|
|
51
|
+
"NetworkError",
|
|
52
|
+
"NotFoundError",
|
|
53
|
+
"PlanLimitError",
|
|
54
|
+
"QuotaExceededError",
|
|
55
|
+
"RateLimitError",
|
|
56
|
+
"EmailPriority",
|
|
57
|
+
"ErrorCode",
|
|
58
|
+
"KeplarsConfig",
|
|
59
|
+
"EmailRecipient",
|
|
60
|
+
"SendEmailRequest",
|
|
61
|
+
"SendEmailResponse",
|
|
62
|
+
"SendEmailData",
|
|
63
|
+
"ScheduleEmailRequest",
|
|
64
|
+
"ScheduledEmailResponse",
|
|
65
|
+
"Contact",
|
|
66
|
+
"Audience",
|
|
67
|
+
"Automation",
|
|
68
|
+
"DomainListItem",
|
|
69
|
+
"PaginatedMeta",
|
|
70
|
+
"ErrorDetail",
|
|
71
|
+
"RateLimitInfo",
|
|
72
|
+
"verify_webhook_signature",
|
|
73
|
+
"render_template",
|
|
74
|
+
]
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
from typing import Any, Dict, Optional, TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
if TYPE_CHECKING:
|
|
4
|
+
from .client import Keplars, AsyncKeplars
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class AudiencesResource:
|
|
8
|
+
def __init__(self, client: "Keplars") -> None:
|
|
9
|
+
self._client = client
|
|
10
|
+
|
|
11
|
+
def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
|
|
12
|
+
body: Dict[str, Any] = {"name": name}
|
|
13
|
+
if description is not None:
|
|
14
|
+
body["description"] = description
|
|
15
|
+
response_data, _ = self._client._request(
|
|
16
|
+
"POST", "/api/v1/public/audiences/add-audience", body
|
|
17
|
+
)
|
|
18
|
+
return response_data
|
|
19
|
+
|
|
20
|
+
def list(self, page: Optional[int] = None, limit: Optional[int] = None) -> Dict[str, Any]:
|
|
21
|
+
params: Dict[str, Any] = {}
|
|
22
|
+
if page is not None:
|
|
23
|
+
params["page"] = page
|
|
24
|
+
if limit is not None:
|
|
25
|
+
params["limit"] = limit
|
|
26
|
+
|
|
27
|
+
query = ""
|
|
28
|
+
if params:
|
|
29
|
+
query = "?" + "&".join(f"{k}={v}" for k, v in params.items())
|
|
30
|
+
|
|
31
|
+
response_data, _ = self._client._request(
|
|
32
|
+
"GET", f"/api/v1/public/audiences/get-audiences{query}"
|
|
33
|
+
)
|
|
34
|
+
return response_data
|
|
35
|
+
|
|
36
|
+
def get(self, id: str) -> Dict[str, Any]:
|
|
37
|
+
response_data, _ = self._client._request(
|
|
38
|
+
"GET", f"/api/v1/public/audiences/get-audience?id={id}"
|
|
39
|
+
)
|
|
40
|
+
return response_data
|
|
41
|
+
|
|
42
|
+
def delete(self, id: str) -> Dict[str, Any]:
|
|
43
|
+
response_data, _ = self._client._request(
|
|
44
|
+
"DELETE", f"/api/v1/public/audiences/delete-audience?id={id}"
|
|
45
|
+
)
|
|
46
|
+
return response_data
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class AsyncAudiencesResource:
|
|
50
|
+
def __init__(self, client: "AsyncKeplars") -> None:
|
|
51
|
+
self._client = client
|
|
52
|
+
|
|
53
|
+
async def create(self, name: str, description: Optional[str] = None) -> Dict[str, Any]:
|
|
54
|
+
body: Dict[str, Any] = {"name": name}
|
|
55
|
+
if description is not None:
|
|
56
|
+
body["description"] = description
|
|
57
|
+
response_data, _ = await self._client._request(
|
|
58
|
+
"POST", "/api/v1/public/audiences/add-audience", body
|
|
59
|
+
)
|
|
60
|
+
return response_data
|
|
61
|
+
|
|
62
|
+
async def list(
|
|
63
|
+
self, page: Optional[int] = None, limit: Optional[int] = None
|
|
64
|
+
) -> Dict[str, Any]:
|
|
65
|
+
params: Dict[str, Any] = {}
|
|
66
|
+
if page is not None:
|
|
67
|
+
params["page"] = page
|
|
68
|
+
if limit is not None:
|
|
69
|
+
params["limit"] = limit
|
|
70
|
+
|
|
71
|
+
query = ""
|
|
72
|
+
if params:
|
|
73
|
+
query = "?" + "&".join(f"{k}={v}" for k, v in params.items())
|
|
74
|
+
|
|
75
|
+
response_data, _ = await self._client._request(
|
|
76
|
+
"GET", f"/api/v1/public/audiences/get-audiences{query}"
|
|
77
|
+
)
|
|
78
|
+
return response_data
|
|
79
|
+
|
|
80
|
+
async def get(self, id: str) -> Dict[str, Any]:
|
|
81
|
+
response_data, _ = await self._client._request(
|
|
82
|
+
"GET", f"/api/v1/public/audiences/get-audience?id={id}"
|
|
83
|
+
)
|
|
84
|
+
return response_data
|
|
85
|
+
|
|
86
|
+
async def delete(self, id: str) -> Dict[str, Any]:
|
|
87
|
+
response_data, _ = await self._client._request(
|
|
88
|
+
"DELETE", f"/api/v1/public/audiences/delete-audience?id={id}"
|
|
89
|
+
)
|
|
90
|
+
return response_data
|