sendstack 0.1.2__tar.gz → 0.1.3__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.
- {sendstack-0.1.2/src/sendstack.egg-info → sendstack-0.1.3}/PKG-INFO +8 -6
- {sendstack-0.1.2 → sendstack-0.1.3}/README.md +7 -5
- {sendstack-0.1.2 → sendstack-0.1.3}/pyproject.toml +1 -1
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/types.py +4 -2
- {sendstack-0.1.2 → sendstack-0.1.3/src/sendstack.egg-info}/PKG-INFO +8 -6
- {sendstack-0.1.2 → sendstack-0.1.3}/tests/test_sendstack.py +14 -14
- {sendstack-0.1.2 → sendstack-0.1.3}/LICENSE +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/setup.cfg +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/__init__.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/client.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/errors.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/files.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/py.typed +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack/utils.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack.egg-info/SOURCES.txt +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack.egg-info/dependency_links.txt +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack.egg-info/requires.txt +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/src/sendstack.egg-info/top_level.txt +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/tests/test_conformance.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/tests/test_distribution_identity.py +0 -0
- {sendstack-0.1.2 → sendstack-0.1.3}/tests/test_files.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sendstack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Sync and async Python SDK for the SendStack email SaaS API.
|
|
5
5
|
Author: Noria Labs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -123,11 +123,13 @@ decoded payload; on `AsyncSendstack` the same call returns a coroutine you
|
|
|
123
123
|
|
|
124
124
|
### Base URL
|
|
125
125
|
|
|
126
|
-
The SDK defaults to `https://
|
|
127
|
-
|
|
126
|
+
The SDK defaults to `https://sendstack.norialabs.com/api/v1` (the versioned API
|
|
127
|
+
base). Override `base_url` to point at another environment — include the
|
|
128
|
+
`/api/v1` version segment, since resource paths (e.g. `/emails`) are sent
|
|
129
|
+
relative to whatever base you provide:
|
|
128
130
|
|
|
129
131
|
```python
|
|
130
|
-
client = Sendstack(token, base_url="https://
|
|
132
|
+
client = Sendstack(token, base_url="https://staging.norialabs.com/api/v1")
|
|
131
133
|
```
|
|
132
134
|
|
|
133
135
|
## Docs Split
|
|
@@ -139,7 +141,7 @@ The SaaS docs remain the canonical source for product/API behavior: account
|
|
|
139
141
|
setup, API tokens, domain verification, DNS records, webhook event catalogs,
|
|
140
142
|
deliverability concepts, provider behavior, dashboard workflows, and the raw
|
|
141
143
|
HTTP API reference. Current live SaaS docs are at
|
|
142
|
-
`https://
|
|
144
|
+
`https://sendstack.norialabs.com/api/docs`.
|
|
143
145
|
|
|
144
146
|
## Auth
|
|
145
147
|
|
|
@@ -162,7 +164,7 @@ request (sync or async callables both work):
|
|
|
162
164
|
from sendstack import BearerAuthStrategy, Sendstack
|
|
163
165
|
|
|
164
166
|
client = Sendstack(
|
|
165
|
-
base_url="https://
|
|
167
|
+
base_url="https://sendstack.norialabs.com/api/v1",
|
|
166
168
|
auth=BearerAuthStrategy(token=lambda context: get_fresh_token()),
|
|
167
169
|
)
|
|
168
170
|
```
|
|
@@ -96,11 +96,13 @@ decoded payload; on `AsyncSendstack` the same call returns a coroutine you
|
|
|
96
96
|
|
|
97
97
|
### Base URL
|
|
98
98
|
|
|
99
|
-
The SDK defaults to `https://
|
|
100
|
-
|
|
99
|
+
The SDK defaults to `https://sendstack.norialabs.com/api/v1` (the versioned API
|
|
100
|
+
base). Override `base_url` to point at another environment — include the
|
|
101
|
+
`/api/v1` version segment, since resource paths (e.g. `/emails`) are sent
|
|
102
|
+
relative to whatever base you provide:
|
|
101
103
|
|
|
102
104
|
```python
|
|
103
|
-
client = Sendstack(token, base_url="https://
|
|
105
|
+
client = Sendstack(token, base_url="https://staging.norialabs.com/api/v1")
|
|
104
106
|
```
|
|
105
107
|
|
|
106
108
|
## Docs Split
|
|
@@ -112,7 +114,7 @@ The SaaS docs remain the canonical source for product/API behavior: account
|
|
|
112
114
|
setup, API tokens, domain verification, DNS records, webhook event catalogs,
|
|
113
115
|
deliverability concepts, provider behavior, dashboard workflows, and the raw
|
|
114
116
|
HTTP API reference. Current live SaaS docs are at
|
|
115
|
-
`https://
|
|
117
|
+
`https://sendstack.norialabs.com/api/docs`.
|
|
116
118
|
|
|
117
119
|
## Auth
|
|
118
120
|
|
|
@@ -135,7 +137,7 @@ request (sync or async callables both work):
|
|
|
135
137
|
from sendstack import BearerAuthStrategy, Sendstack
|
|
136
138
|
|
|
137
139
|
client = Sendstack(
|
|
138
|
-
base_url="https://
|
|
140
|
+
base_url="https://sendstack.norialabs.com/api/v1",
|
|
139
141
|
auth=BearerAuthStrategy(token=lambda context: get_fresh_token()),
|
|
140
142
|
)
|
|
141
143
|
```
|
|
@@ -20,8 +20,10 @@ from typing import Any, Literal, NotRequired, TypeAlias, TypedDict
|
|
|
20
20
|
|
|
21
21
|
import httpx
|
|
22
22
|
|
|
23
|
-
# The
|
|
24
|
-
|
|
23
|
+
# The versioned API base. Override via ``base_url`` for other environments;
|
|
24
|
+
# include the /api/v1 segment, since resource paths (e.g. /emails) are sent
|
|
25
|
+
# relative to whatever base is configured.
|
|
26
|
+
DEFAULT_BASE_URL = "https://sendstack.norialabs.com/api/v1"
|
|
25
27
|
|
|
26
28
|
# Sentinel distinguishing "no body" from an explicit ``None`` body.
|
|
27
29
|
UNSET: Any = object()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sendstack
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.3
|
|
4
4
|
Summary: Sync and async Python SDK for the SendStack email SaaS API.
|
|
5
5
|
Author: Noria Labs
|
|
6
6
|
License-Expression: MIT
|
|
@@ -123,11 +123,13 @@ decoded payload; on `AsyncSendstack` the same call returns a coroutine you
|
|
|
123
123
|
|
|
124
124
|
### Base URL
|
|
125
125
|
|
|
126
|
-
The SDK defaults to `https://
|
|
127
|
-
|
|
126
|
+
The SDK defaults to `https://sendstack.norialabs.com/api/v1` (the versioned API
|
|
127
|
+
base). Override `base_url` to point at another environment — include the
|
|
128
|
+
`/api/v1` version segment, since resource paths (e.g. `/emails`) are sent
|
|
129
|
+
relative to whatever base you provide:
|
|
128
130
|
|
|
129
131
|
```python
|
|
130
|
-
client = Sendstack(token, base_url="https://
|
|
132
|
+
client = Sendstack(token, base_url="https://staging.norialabs.com/api/v1")
|
|
131
133
|
```
|
|
132
134
|
|
|
133
135
|
## Docs Split
|
|
@@ -139,7 +141,7 @@ The SaaS docs remain the canonical source for product/API behavior: account
|
|
|
139
141
|
setup, API tokens, domain verification, DNS records, webhook event catalogs,
|
|
140
142
|
deliverability concepts, provider behavior, dashboard workflows, and the raw
|
|
141
143
|
HTTP API reference. Current live SaaS docs are at
|
|
142
|
-
`https://
|
|
144
|
+
`https://sendstack.norialabs.com/api/docs`.
|
|
143
145
|
|
|
144
146
|
## Auth
|
|
145
147
|
|
|
@@ -162,7 +164,7 @@ request (sync or async callables both work):
|
|
|
162
164
|
from sendstack import BearerAuthStrategy, Sendstack
|
|
163
165
|
|
|
164
166
|
client = Sendstack(
|
|
165
|
-
base_url="https://
|
|
167
|
+
base_url="https://sendstack.norialabs.com/api/v1",
|
|
166
168
|
auth=BearerAuthStrategy(token=lambda context: get_fresh_token()),
|
|
167
169
|
)
|
|
168
170
|
```
|
|
@@ -131,7 +131,7 @@ def test_send_email_aliases_and_unwraps():
|
|
|
131
131
|
|
|
132
132
|
assert result == {"id": "m_1", "status": "queued"}
|
|
133
133
|
request = calls[0]
|
|
134
|
-
assert str(request.url) == "https://
|
|
134
|
+
assert str(request.url) == "https://sendstack.norialabs.com/api/v1/emails"
|
|
135
135
|
assert request.method == "POST"
|
|
136
136
|
assert request.headers["authorization"] == "Bearer tok"
|
|
137
137
|
assert request.headers["accept"] == "application/json"
|
|
@@ -192,10 +192,10 @@ def test_emails_get_events_cancel_requeue():
|
|
|
192
192
|
assert client.emails.requeue("m1")["status"] == "queued"
|
|
193
193
|
finally:
|
|
194
194
|
http.close()
|
|
195
|
-
assert calls[0].url.path == "/emails/m 1" # decoded back by httpx (sent percent-encoded)
|
|
196
|
-
assert calls[1].url.path == "/emails/m1/events"
|
|
197
|
-
assert calls[2].method == "POST" and calls[2].url.path == "/emails/m1/cancel"
|
|
198
|
-
assert calls[3].url.path == "/emails/m1/requeue"
|
|
195
|
+
assert calls[0].url.path == "/api/v1/emails/m 1" # decoded back by httpx (sent percent-encoded)
|
|
196
|
+
assert calls[1].url.path == "/api/v1/emails/m1/events"
|
|
197
|
+
assert calls[2].method == "POST" and calls[2].url.path == "/api/v1/emails/m1/cancel"
|
|
198
|
+
assert calls[3].url.path == "/api/v1/emails/m1/requeue"
|
|
199
199
|
|
|
200
200
|
|
|
201
201
|
# --------------------------------------------------------------------------- #
|
|
@@ -224,8 +224,8 @@ def test_domains_resource():
|
|
|
224
224
|
"provider_id": "p1",
|
|
225
225
|
"custom_return_path": "bounce",
|
|
226
226
|
}
|
|
227
|
-
assert calls[1].method == "GET" and calls[1].url.path == "/domains"
|
|
228
|
-
assert calls[3].url.path == "/domains/d1/verify"
|
|
227
|
+
assert calls[1].method == "GET" and calls[1].url.path == "/api/v1/domains"
|
|
228
|
+
assert calls[3].url.path == "/api/v1/domains/d1/verify"
|
|
229
229
|
|
|
230
230
|
|
|
231
231
|
def test_templates_resource_including_delete_returns_none():
|
|
@@ -247,7 +247,7 @@ def test_templates_resource_including_delete_returns_none():
|
|
|
247
247
|
finally:
|
|
248
248
|
http.close()
|
|
249
249
|
assert removed is None
|
|
250
|
-
assert calls[3].method == "PATCH" and calls[3].url.path == "/templates/t1"
|
|
250
|
+
assert calls[3].method == "PATCH" and calls[3].url.path == "/api/v1/templates/t1"
|
|
251
251
|
assert calls[4].method == "DELETE"
|
|
252
252
|
|
|
253
253
|
|
|
@@ -268,8 +268,8 @@ def test_webhooks_resource_event_types_alias():
|
|
|
268
268
|
finally:
|
|
269
269
|
http.close()
|
|
270
270
|
assert json.loads(calls[0].content) == {"url": "https://e.com", "event_types": ["email.sent"]}
|
|
271
|
-
assert calls[0].url.path == "/webhook-endpoints"
|
|
272
|
-
assert calls[3].method == "DELETE" and calls[3].url.path == "/webhook-endpoints/wh"
|
|
271
|
+
assert calls[0].url.path == "/api/v1/webhook-endpoints"
|
|
272
|
+
assert calls[3].method == "DELETE" and calls[3].url.path == "/api/v1/webhook-endpoints/wh"
|
|
273
273
|
|
|
274
274
|
|
|
275
275
|
def test_webhook_events_retry_alias_attribute():
|
|
@@ -280,7 +280,7 @@ def test_webhook_events_retry_alias_attribute():
|
|
|
280
280
|
finally:
|
|
281
281
|
http.close()
|
|
282
282
|
assert result["webhook_status"] == "queued"
|
|
283
|
-
assert calls[0].method == "POST" and calls[0].url.path == "/events/ev_1/retry"
|
|
283
|
+
assert calls[0].method == "POST" and calls[0].url.path == "/api/v1/events/ev_1/retry"
|
|
284
284
|
|
|
285
285
|
|
|
286
286
|
def test_suppressions_resource():
|
|
@@ -297,8 +297,8 @@ def test_suppressions_resource():
|
|
|
297
297
|
client.suppressions.remove("bad@x.com")
|
|
298
298
|
finally:
|
|
299
299
|
http.close()
|
|
300
|
-
assert calls[0].url.path == "/suppressions"
|
|
301
|
-
assert calls[2].method == "DELETE" and calls[2].url.path == "/suppressions/bad@x.com"
|
|
300
|
+
assert calls[0].url.path == "/api/v1/suppressions"
|
|
301
|
+
assert calls[2].method == "DELETE" and calls[2].url.path == "/api/v1/suppressions/bad@x.com"
|
|
302
302
|
|
|
303
303
|
|
|
304
304
|
def test_attachments_upload_alias():
|
|
@@ -646,7 +646,7 @@ def test_close_owns_vs_injected_and_context_manager():
|
|
|
646
646
|
def test_default_base_url_when_unspecified():
|
|
647
647
|
client = Sendstack("tok")
|
|
648
648
|
try:
|
|
649
|
-
assert client.base_url == "https://
|
|
649
|
+
assert client.base_url == "https://sendstack.norialabs.com/api/v1"
|
|
650
650
|
finally:
|
|
651
651
|
client.close()
|
|
652
652
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|