broadcast-python 0.4.0__tar.gz → 0.5.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.
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/CHANGELOG.md +26 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/PKG-INFO +10 -2
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/README.md +9 -1
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/pyproject.toml +1 -1
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/__init__.py +2 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/autopilots.py +2 -1
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/opt_in_forms.py +9 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/subscribers.py +5 -1
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/version.py +1 -1
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/webhook.py +2 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/.gitignore +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/LICENSE +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/client.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/configuration.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/connection.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/errors.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/py.typed +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/__init__.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/base.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/broadcasts.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/channel_design.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/discovery.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/email_servers.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/global_suppressions.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/migration.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/segments.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/sequences.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/suppressions.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/templates.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/topics.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/transactionals.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/users.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/webhook_endpoints.py +0 -0
- {broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/response.py +0 -0
|
@@ -4,6 +4,32 @@ All notable changes to this project will be documented in this file.
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.5.0] - 2026-10-10
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- `email.send_delayed` and `broadcast.batch_completed` in `EVENT_TYPES` (and in
|
|
12
|
+
`EMAIL_EVENTS` / `BROADCAST_EVENTS`), matching the server (Broadcast 2.43.0).
|
|
13
|
+
`email.send_delayed` fires when a transactional email waits for room under
|
|
14
|
+
its server's hourly limit.
|
|
15
|
+
- `excluded_segment_ids` on broadcasts, sequences and autopilots: segments a
|
|
16
|
+
send never reaches. The server refuses a segment that is both sent to and
|
|
17
|
+
excluded with 422.
|
|
18
|
+
- `subscribers.create(unsubscribed_at=...)`: creates a subscriber who has
|
|
19
|
+
already unsubscribed, in one request, with any token. Before, the server
|
|
20
|
+
ignored the field and a migration had to create, then unsubscribe.
|
|
21
|
+
|
|
22
|
+
- `TRIGGER_FREQUENCIES`: the words `trigger_settings["frequency"]` accepts
|
|
23
|
+
(`always`, `every_visit`, `once_per_session`, `once_per_day`,
|
|
24
|
+
`once_per_week`, `once`).
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Opt-in forms: the server now refuses an unknown `trigger_settings`
|
|
29
|
+
frequency word with 422 (`ValidationError`). Before, it saved any word, and
|
|
30
|
+
an unknown one showed the popup on every visit. The client still sends what
|
|
31
|
+
it is given.
|
|
32
|
+
|
|
7
33
|
## [0.4.0] - 2026-10-06
|
|
8
34
|
|
|
9
35
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: broadcast-python
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.5.0
|
|
4
4
|
Summary: Python client for the Broadcast email platform. Subscribers, sequences, broadcasts, segments, templates, autopilot, webhooks, and transactional email.
|
|
5
5
|
Project-URL: Homepage, https://sendbroadcast.net
|
|
6
6
|
Project-URL: Repository, https://github.com/send-broadcast/broadcast-python
|
|
@@ -240,6 +240,8 @@ client.sequences.move_step(id, step_id, under_id)
|
|
|
240
240
|
client.segments.create(name="VIPs")
|
|
241
241
|
client.templates.create(label="Welcome", subject="Hi", body="...")
|
|
242
242
|
client.opt_in_forms.analytics(id, start_date=date(2026, 1, 1))
|
|
243
|
+
# How often the same visitor sees a popup: one of TRIGGER_FREQUENCIES, or ValidationError (422).
|
|
244
|
+
client.opt_in_forms.update(id, trigger_settings={"frequency": "once_per_day"})
|
|
243
245
|
client.opt_in_forms.create_variant(id, name="B", weight=50)
|
|
244
246
|
client.opt_in_forms.duplicate(id, label="Copy")
|
|
245
247
|
```
|
|
@@ -264,6 +266,12 @@ client.topics.delete(topic["id"]) # 422 while a broadcast or sequence uses it
|
|
|
264
266
|
# Send to a topic: (segments) AND topic
|
|
265
267
|
client.broadcasts.create(subject="Webinar", body="...", segment_ids=[2], topic_id=topic["id"])
|
|
266
268
|
|
|
269
|
+
# Send to everyone except a segment (also on sequences and autopilots)
|
|
270
|
+
client.broadcasts.create(subject="Offer", body="...", excluded_segment_ids=[competitors["id"]])
|
|
271
|
+
|
|
272
|
+
# Migrate someone who already unsubscribed, in one request
|
|
273
|
+
client.subscribers.create(email="opted-out@example.com", unsubscribed_at="2025-03-14T09:30:00Z")
|
|
274
|
+
|
|
267
275
|
# Change only the keys you send (None deletes a key); the default replaces custom_data
|
|
268
276
|
client.subscribers.update("jane@example.com", custom_data={"sub_webinars": False}, custom_data_mode="merge")
|
|
269
277
|
```
|
|
@@ -439,7 +447,7 @@ every rejection rather than distinguishing them.
|
|
|
439
447
|
Pass the **raw** request body. Re-serialising a parsed dict changes the bytes
|
|
440
448
|
and verification will fail.
|
|
441
449
|
|
|
442
|
-
`broadcast_python.EVENT_TYPES` lists all
|
|
450
|
+
`broadcast_python.EVENT_TYPES` lists all 37 event names. `SUBSCRIBER_EVENTS`
|
|
443
451
|
includes `subscribers.purged` and `subscribers.purge_failed`: a purge of the
|
|
444
452
|
whole list sends one of these instead of a `subscriber.deleted` per subscriber.
|
|
445
453
|
|
|
@@ -216,6 +216,8 @@ client.sequences.move_step(id, step_id, under_id)
|
|
|
216
216
|
client.segments.create(name="VIPs")
|
|
217
217
|
client.templates.create(label="Welcome", subject="Hi", body="...")
|
|
218
218
|
client.opt_in_forms.analytics(id, start_date=date(2026, 1, 1))
|
|
219
|
+
# How often the same visitor sees a popup: one of TRIGGER_FREQUENCIES, or ValidationError (422).
|
|
220
|
+
client.opt_in_forms.update(id, trigger_settings={"frequency": "once_per_day"})
|
|
219
221
|
client.opt_in_forms.create_variant(id, name="B", weight=50)
|
|
220
222
|
client.opt_in_forms.duplicate(id, label="Copy")
|
|
221
223
|
```
|
|
@@ -240,6 +242,12 @@ client.topics.delete(topic["id"]) # 422 while a broadcast or sequence uses it
|
|
|
240
242
|
# Send to a topic: (segments) AND topic
|
|
241
243
|
client.broadcasts.create(subject="Webinar", body="...", segment_ids=[2], topic_id=topic["id"])
|
|
242
244
|
|
|
245
|
+
# Send to everyone except a segment (also on sequences and autopilots)
|
|
246
|
+
client.broadcasts.create(subject="Offer", body="...", excluded_segment_ids=[competitors["id"]])
|
|
247
|
+
|
|
248
|
+
# Migrate someone who already unsubscribed, in one request
|
|
249
|
+
client.subscribers.create(email="opted-out@example.com", unsubscribed_at="2025-03-14T09:30:00Z")
|
|
250
|
+
|
|
243
251
|
# Change only the keys you send (None deletes a key); the default replaces custom_data
|
|
244
252
|
client.subscribers.update("jane@example.com", custom_data={"sub_webinars": False}, custom_data_mode="merge")
|
|
245
253
|
```
|
|
@@ -415,7 +423,7 @@ every rejection rather than distinguishing them.
|
|
|
415
423
|
Pass the **raw** request body. Re-serialising a parsed dict changes the bytes
|
|
416
424
|
and verification will fail.
|
|
417
425
|
|
|
418
|
-
`broadcast_python.EVENT_TYPES` lists all
|
|
426
|
+
`broadcast_python.EVENT_TYPES` lists all 37 event names. `SUBSCRIBER_EVENTS`
|
|
419
427
|
includes `subscribers.purged` and `subscribers.purge_failed`: a purge of the
|
|
420
428
|
whole list sends one of these instead of a `subscriber.deleted` per subscriber.
|
|
421
429
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "broadcast-python"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.5.0"
|
|
8
8
|
description = "Python client for the Broadcast email platform. Subscribers, sequences, broadcasts, segments, templates, autopilot, webhooks, and transactional email."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.9"
|
|
@@ -28,6 +28,7 @@ from .errors import (
|
|
|
28
28
|
)
|
|
29
29
|
from .resources.email_servers import REDACTED_FIELDS
|
|
30
30
|
from .resources.migration import COLLECTIONS
|
|
31
|
+
from .resources.opt_in_forms import TRIGGER_FREQUENCIES
|
|
31
32
|
from .resources.transactionals import MAX_IDEMPOTENCY_KEY_LENGTH
|
|
32
33
|
from .response import RateLimit, Response, Warning_
|
|
33
34
|
from .version import VERSION
|
|
@@ -42,6 +43,7 @@ __all__ = [
|
|
|
42
43
|
"EVENT_TYPES",
|
|
43
44
|
"MAX_IDEMPOTENCY_KEY_LENGTH",
|
|
44
45
|
"REDACTED_FIELDS",
|
|
46
|
+
"TRIGGER_FREQUENCIES",
|
|
45
47
|
"VERSION",
|
|
46
48
|
"WARNINGS_MODES",
|
|
47
49
|
"APIError",
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/autopilots.py
RENAMED
|
@@ -36,7 +36,8 @@ class Autopilots(BaseResource):
|
|
|
36
36
|
write-only. Scheduling takes ``schedule_frequency`` (daily, weekly,
|
|
37
37
|
biweekly, monthly), ``schedule_day_of_week``, ``schedule_day_of_month``,
|
|
38
38
|
``schedule_time``, ``schedule_timezone``. ``segment_ids`` restricts the
|
|
39
|
-
newsletter's audience
|
|
39
|
+
newsletter's audience; ``excluded_segment_ids`` lists segments its
|
|
40
|
+
drafts never reach.
|
|
40
41
|
"""
|
|
41
42
|
return self._post("/api/v1/autopilots", {"autopilot": attrs})
|
|
42
43
|
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/opt_in_forms.py
RENAMED
|
@@ -5,6 +5,12 @@ from .base import BaseResource, compact
|
|
|
5
5
|
|
|
6
6
|
Id = Union[str, int]
|
|
7
7
|
|
|
8
|
+
#: The words ``trigger_settings["frequency"]`` accepts: how often the same
|
|
9
|
+
#: visitor sees a popup. ``always`` and ``every_visit`` mean the same. The server
|
|
10
|
+
#: refuses any other word with 422 (:class:`ValidationError`); the client does
|
|
11
|
+
#: not check, so an older server is never refused a word it would take.
|
|
12
|
+
TRIGGER_FREQUENCIES = ("always", "every_visit", "once_per_session", "once_per_day", "once_per_week", "once")
|
|
13
|
+
|
|
8
14
|
|
|
9
15
|
class OptInForms(BaseResource):
|
|
10
16
|
def list(self, **params: Any) -> Any:
|
|
@@ -23,6 +29,9 @@ class OptInForms(BaseResource):
|
|
|
23
29
|
Nested settings dicts (``theme_settings``, ``automation_settings``,
|
|
24
30
|
``security_settings``, ``trigger_settings``, ``widget_settings``) and
|
|
25
31
|
the block arrays are passed through verbatim.
|
|
32
|
+
``trigger_settings["frequency"]`` must be one of
|
|
33
|
+
:data:`TRIGGER_FREQUENCIES`; any other word raises
|
|
34
|
+
:class:`ValidationError` (422).
|
|
26
35
|
"""
|
|
27
36
|
return self._post("/api/v1/opt_in_forms", {"opt_in_form": attrs})
|
|
28
37
|
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/subscribers.py
RENAMED
|
@@ -33,7 +33,11 @@ class Subscribers(BaseResource):
|
|
|
33
33
|
timestamp when migrating an already-confirmed list off another provider.
|
|
34
34
|
It is ignored (with a warning) on update.
|
|
35
35
|
|
|
36
|
-
``unsubscribed_at``
|
|
36
|
+
``unsubscribed_at`` (any token, create only, ISO 8601) stores the
|
|
37
|
+
subscriber as unsubscribed in the same request, for migrating a list
|
|
38
|
+
with its opt-outs intact: no confirmation email, 422 if it is in the
|
|
39
|
+
future or sent with ``is_active=True``. To unsubscribe an existing
|
|
40
|
+
subscriber, use :meth:`unsubscribe`.
|
|
37
41
|
"""
|
|
38
42
|
double_opt_in = attrs.pop("double_opt_in", None)
|
|
39
43
|
confirmation_template_id = attrs.pop("confirmation_template_id", None)
|
|
@@ -15,6 +15,7 @@ EMAIL_EVENTS = (
|
|
|
15
15
|
"email.sent",
|
|
16
16
|
"email.delivered",
|
|
17
17
|
"email.delivery_delayed",
|
|
18
|
+
"email.send_delayed",
|
|
18
19
|
"email.complained",
|
|
19
20
|
"email.bounced",
|
|
20
21
|
"email.opened",
|
|
@@ -45,6 +46,7 @@ BROADCAST_EVENTS = (
|
|
|
45
46
|
"broadcast.partial_failure",
|
|
46
47
|
"broadcast.aborted",
|
|
47
48
|
"broadcast.paused",
|
|
49
|
+
"broadcast.batch_completed",
|
|
48
50
|
)
|
|
49
51
|
|
|
50
52
|
SEQUENCE_EVENTS = (
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/broadcasts.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/channel_design.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/discovery.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/email_servers.py
RENAMED
|
File without changes
|
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/migration.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/segments.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/sequences.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/suppressions.py
RENAMED
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/templates.py
RENAMED
|
File without changes
|
|
File without changes
|
{broadcast_python-0.4.0 → broadcast_python-0.5.0}/src/broadcast_python/resources/transactionals.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|