simplepush 3.6.1__tar.gz → 3.7.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.
- {simplepush-3.6.1 → simplepush-3.7.0}/PKG-INFO +4 -3
- {simplepush-3.6.1 → simplepush-3.7.0}/README.md +3 -2
- {simplepush-3.6.1 → simplepush-3.7.0}/pyproject.toml +1 -1
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/api.py +37 -15
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/client.py +4 -2
- {simplepush-3.6.1 → simplepush-3.7.0}/.gitignore +0 -0
- {simplepush-3.6.1 → simplepush-3.7.0}/LICENSE +0 -0
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/__init__.py +0 -0
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/_extras.py +0 -0
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/crypto.py +0 -0
- {simplepush-3.6.1 → simplepush-3.7.0}/src/simplepush/decrypt.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: simplepush
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.7.0
|
|
4
4
|
Summary: Python client for Simplepush (tasks, notifications, events, end-to-end encryption).
|
|
5
5
|
Project-URL: Homepage, https://simplepu.sh
|
|
6
6
|
Project-URL: Documentation, https://simplepu.sh/guide/python-sdk
|
|
@@ -113,8 +113,9 @@ form at once (by default each filled input arrives as an intermediate
|
|
|
113
113
|
set); `reply=ReplyMode.STICKY` (or `"one-shot"` / `"one-time-per-user"`) shows
|
|
114
114
|
recipients an in-thread reply composer (collect via `replies()`);
|
|
115
115
|
`content_format=ContentFormat.MARKDOWN` renders a task's `content` as
|
|
116
|
-
Markdown (notifications are always plain); `
|
|
117
|
-
|
|
116
|
+
Markdown (notifications are always plain); `priority=` sets how loudly the
|
|
117
|
+
push interrupts, 1 (minimal) to 5 (critical; sounds even on a muted phone),
|
|
118
|
+
default 3, with `critical_volume=` (0 to 1) for level 5 on iOS.
|
|
118
119
|
|
|
119
120
|
A task can have **subtasks** appended to its chain. A subtask inherits the
|
|
120
121
|
parent's recipients and encryption (no target, no password); its `inputs()` /
|
|
@@ -63,8 +63,9 @@ form at once (by default each filled input arrives as an intermediate
|
|
|
63
63
|
set); `reply=ReplyMode.STICKY` (or `"one-shot"` / `"one-time-per-user"`) shows
|
|
64
64
|
recipients an in-thread reply composer (collect via `replies()`);
|
|
65
65
|
`content_format=ContentFormat.MARKDOWN` renders a task's `content` as
|
|
66
|
-
Markdown (notifications are always plain); `
|
|
67
|
-
|
|
66
|
+
Markdown (notifications are always plain); `priority=` sets how loudly the
|
|
67
|
+
push interrupts, 1 (minimal) to 5 (critical; sounds even on a muted phone),
|
|
68
|
+
default 3, with `critical_volume=` (0 to 1) for level 5 on iOS.
|
|
68
69
|
|
|
69
70
|
A task can have **subtasks** appended to its chain. A subtask inherits the
|
|
70
71
|
parent's recipients and encryption (no target, no password); its `inputs()` /
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "simplepush"
|
|
7
|
-
version = "3.
|
|
7
|
+
version = "3.7.0"
|
|
8
8
|
description = "Python client for Simplepush (tasks, notifications, events, end-to-end encryption)."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = { file = "LICENSE" }
|
|
@@ -62,6 +62,27 @@ from .client import (
|
|
|
62
62
|
|
|
63
63
|
# --- Wire serialization helpers ---
|
|
64
64
|
|
|
65
|
+
def _priority_wire(priority, critical, critical_volume) -> dict:
|
|
66
|
+
"""The `priority` / `criticalVolume` fields of a create request. `priority`
|
|
67
|
+
is 1 (minimal) to 5 (critical), absent = 3; the deprecated `critical` flag
|
|
68
|
+
means 5 when no priority is given. `critical_volume` (0 < v <= 1) is the
|
|
69
|
+
iOS critical alert volume and is only valid with level 5."""
|
|
70
|
+
level = priority if priority is not None else (5 if critical else None)
|
|
71
|
+
if level is not None and (not isinstance(level, int) or isinstance(level, bool) or not 1 <= level <= 5):
|
|
72
|
+
raise ValueError("priority must be an integer between 1 and 5")
|
|
73
|
+
if critical_volume is not None:
|
|
74
|
+
if level != 5:
|
|
75
|
+
raise ValueError("critical_volume applies to priority 5 only")
|
|
76
|
+
if not 0 < critical_volume <= 1:
|
|
77
|
+
raise ValueError("critical_volume must be greater than 0 and at most 1")
|
|
78
|
+
out: dict = {}
|
|
79
|
+
if level is not None:
|
|
80
|
+
out["priority"] = level
|
|
81
|
+
if critical_volume is not None:
|
|
82
|
+
out["criticalVolume"] = critical_volume
|
|
83
|
+
return out
|
|
84
|
+
|
|
85
|
+
|
|
65
86
|
def _expires_at_wire(value) -> str:
|
|
66
87
|
"""Serialize a task deadline to wire ISO-8601. A naive datetime is
|
|
67
88
|
rejected rather than guessed at — the server compares against UTC."""
|
|
@@ -595,6 +616,8 @@ class _BaseClient:
|
|
|
595
616
|
password: str | None = None,
|
|
596
617
|
tag: str | None = None,
|
|
597
618
|
critical: bool = False,
|
|
619
|
+
priority: int | None = None,
|
|
620
|
+
critical_volume: float | None = None,
|
|
598
621
|
reply: ReplyMode | Literal["one-shot", "sticky", "one-time-per-user"] | None = None,
|
|
599
622
|
content_format: ContentFormat | Literal["plain", "markdown"] | None = None,
|
|
600
623
|
shared: bool = False,
|
|
@@ -667,7 +690,7 @@ class _BaseClient:
|
|
|
667
690
|
links=links, files=files,
|
|
668
691
|
auto_commit=auto_commit,
|
|
669
692
|
password=password if password is not None else self._send_password(topic),
|
|
670
|
-
tag=tag, critical=critical, reply=reply,
|
|
693
|
+
tag=tag, critical=critical, priority=priority, critical_volume=critical_volume, reply=reply,
|
|
671
694
|
content_format=content_format, shared=shared,
|
|
672
695
|
expires_at=expires_at,
|
|
673
696
|
)
|
|
@@ -687,6 +710,8 @@ class _BaseClient:
|
|
|
687
710
|
password: str | None = None,
|
|
688
711
|
tag: str | None = None,
|
|
689
712
|
critical: bool = False,
|
|
713
|
+
priority: int | None = None,
|
|
714
|
+
critical_volume: float | None = None,
|
|
690
715
|
shared: bool = False,
|
|
691
716
|
) -> "Notification | NotificationGroup":
|
|
692
717
|
"""Send a notification and return a handle to its event stream.
|
|
@@ -757,13 +782,13 @@ class _BaseClient:
|
|
|
757
782
|
title=title, content=content, input=input,
|
|
758
783
|
image=image, audio=audio, link=link,
|
|
759
784
|
password=password if password is not None else self._send_password(topic),
|
|
760
|
-
tag=tag, critical=critical, shared=shared,
|
|
785
|
+
tag=tag, critical=critical, priority=priority, critical_volume=critical_volume, shared=shared,
|
|
761
786
|
)
|
|
762
787
|
|
|
763
788
|
def _create_task(self, *, topic=None, member=None, broadcast=False,
|
|
764
789
|
title=None, content=None, inputs=None, links=None,
|
|
765
790
|
files=None,
|
|
766
|
-
auto_commit=False, password=None, tag=None, critical=False,
|
|
791
|
+
auto_commit=False, password=None, tag=None, critical=False, priority=None, critical_volume=None,
|
|
767
792
|
reply=None, content_format=None, shared=False,
|
|
768
793
|
expires_at=None) -> "Task | TaskGroup":
|
|
769
794
|
if not content and not inputs:
|
|
@@ -893,8 +918,7 @@ class _BaseClient:
|
|
|
893
918
|
body["title"] = title
|
|
894
919
|
if content is not None:
|
|
895
920
|
body["content"] = content
|
|
896
|
-
|
|
897
|
-
body["critical"] = critical
|
|
921
|
+
body.update(_priority_wire(priority, critical, critical_volume))
|
|
898
922
|
if reply is not None:
|
|
899
923
|
body["reply"] = reply.value if isinstance(reply, ReplyMode) else reply
|
|
900
924
|
if content_format is not None:
|
|
@@ -971,7 +995,7 @@ class _BaseClient:
|
|
|
971
995
|
|
|
972
996
|
def _create_notification(self, *, topic=None, member=None, broadcast=False,
|
|
973
997
|
title=None, content=None, input=None, image=None, audio=None,
|
|
974
|
-
link=None, password=None, tag=None, critical=False,
|
|
998
|
+
link=None, password=None, tag=None, critical=False, priority=None, critical_volume=None,
|
|
975
999
|
shared=False) -> "Notification | NotificationGroup":
|
|
976
1000
|
if not content and input is None:
|
|
977
1001
|
raise ValueError("Either content or an input must be provided")
|
|
@@ -1098,8 +1122,7 @@ class _BaseClient:
|
|
|
1098
1122
|
payload["choiceInput"] = {"options": choice_options}
|
|
1099
1123
|
elif action_defs is not None:
|
|
1100
1124
|
payload["actionInput"] = {"actions": action_defs}
|
|
1101
|
-
|
|
1102
|
-
payload["critical"] = critical
|
|
1125
|
+
payload.update(_priority_wire(priority, critical, critical_volume))
|
|
1103
1126
|
if encryption_dict is not None:
|
|
1104
1127
|
payload["encryption"] = encryption_dict
|
|
1105
1128
|
if shared:
|
|
@@ -1227,7 +1250,7 @@ class _BaseClient:
|
|
|
1227
1250
|
|
|
1228
1251
|
def _build_subtask_data(self, send_key, *, title=None, content=None, inputs=None,
|
|
1229
1252
|
links=None, files=None,
|
|
1230
|
-
auto_commit=False, critical=False,
|
|
1253
|
+
auto_commit=False, critical=False, priority=None, critical_volume=None,
|
|
1231
1254
|
reply=None, content_format=None) -> "tuple[dict, list]":
|
|
1232
1255
|
"""Build the (encrypted) `data` dict of a subtask append plus the
|
|
1233
1256
|
prepared local attachments awaiting upload — shared by the single-task
|
|
@@ -1320,8 +1343,7 @@ class _BaseClient:
|
|
|
1320
1343
|
data["title"] = title
|
|
1321
1344
|
if content is not None:
|
|
1322
1345
|
data["content"] = content
|
|
1323
|
-
|
|
1324
|
-
data["critical"] = critical
|
|
1346
|
+
data.update(_priority_wire(priority, critical, critical_volume))
|
|
1325
1347
|
if reply is not None:
|
|
1326
1348
|
data["reply"] = reply.value if isinstance(reply, ReplyMode) else reply
|
|
1327
1349
|
if content_format is not None:
|
|
@@ -1332,14 +1354,14 @@ class _BaseClient:
|
|
|
1332
1354
|
|
|
1333
1355
|
def _append_subtask(self, task, *, title=None, content=None, inputs=None,
|
|
1334
1356
|
links=None, files=None,
|
|
1335
|
-
auto_commit=False, critical=False,
|
|
1357
|
+
auto_commit=False, critical=False, priority=None, critical_volume=None,
|
|
1336
1358
|
reply=None, content_format=None) -> Subtask:
|
|
1337
1359
|
if not task.append_token:
|
|
1338
1360
|
raise RuntimeError("this task has no append token; cannot append a subtask")
|
|
1339
1361
|
# Inherit the parent's key (subtask encryption must match the chain's).
|
|
1340
1362
|
data, prepared = self._build_subtask_data(
|
|
1341
1363
|
task._send_key, title=title, content=content, inputs=inputs,
|
|
1342
|
-
links=links, files=files, auto_commit=auto_commit, critical=critical,
|
|
1364
|
+
links=links, files=files, auto_commit=auto_commit, critical=critical, priority=priority, critical_volume=critical_volume,
|
|
1343
1365
|
reply=reply, content_format=content_format,
|
|
1344
1366
|
)
|
|
1345
1367
|
|
|
@@ -1369,7 +1391,7 @@ class _BaseClient:
|
|
|
1369
1391
|
|
|
1370
1392
|
def _append_subtasks_to_group(self, group, *, instances=None, title=None,
|
|
1371
1393
|
content=None, inputs=None, links=None, files=None,
|
|
1372
|
-
auto_commit=False, critical=False,
|
|
1394
|
+
auto_commit=False, critical=False, priority=None, critical_volume=None,
|
|
1373
1395
|
reply=None, content_format=None) -> "list[Subtask]":
|
|
1374
1396
|
"""Append one subtask per member instance to a task group's chains,
|
|
1375
1397
|
atomically, via the group append token. `instances` (task ids) restricts
|
|
@@ -1381,7 +1403,7 @@ class _BaseClient:
|
|
|
1381
1403
|
raise RuntimeError("this task group has no append token; cannot append a subtask")
|
|
1382
1404
|
data, prepared = self._build_subtask_data(
|
|
1383
1405
|
group._send_key, title=title, content=content, inputs=inputs,
|
|
1384
|
-
links=links, files=files, auto_commit=auto_commit, critical=critical,
|
|
1406
|
+
links=links, files=files, auto_commit=auto_commit, critical=critical, priority=priority, critical_volume=critical_volume,
|
|
1385
1407
|
reply=reply, content_format=content_format,
|
|
1386
1408
|
)
|
|
1387
1409
|
|
|
@@ -1472,6 +1472,7 @@ class Task:
|
|
|
1472
1472
|
inputs=None, links: list[str] | None = None,
|
|
1473
1473
|
files: "list[str | os.PathLike] | None" = None,
|
|
1474
1474
|
auto_commit: bool = False, critical: bool = False,
|
|
1475
|
+
priority: int | None = None, critical_volume: float | None = None,
|
|
1475
1476
|
reply: "ReplyMode | Literal['one-shot', 'sticky', 'one-time-per-user'] | None" = None,
|
|
1476
1477
|
content_format: "ContentFormat | Literal['plain', 'markdown'] | None" = None) -> "Subtask":
|
|
1477
1478
|
"""Append a subtask to this task's chain and return a `Subtask` handle.
|
|
@@ -1486,7 +1487,7 @@ class Task:
|
|
|
1486
1487
|
return self._client._append_subtask(
|
|
1487
1488
|
self, title=title, content=content, inputs=inputs,
|
|
1488
1489
|
links=links, files=files,
|
|
1489
|
-
auto_commit=auto_commit, critical=critical, reply=reply,
|
|
1490
|
+
auto_commit=auto_commit, critical=critical, priority=priority, critical_volume=critical_volume, reply=reply,
|
|
1490
1491
|
content_format=content_format,
|
|
1491
1492
|
)
|
|
1492
1493
|
|
|
@@ -1644,6 +1645,7 @@ class TaskGroup:
|
|
|
1644
1645
|
files: "list[str | os.PathLike] | None" = None,
|
|
1645
1646
|
instances: "list[str | Task] | None" = None,
|
|
1646
1647
|
auto_commit: bool = False, critical: bool = False,
|
|
1648
|
+
priority: int | None = None, critical_volume: float | None = None,
|
|
1647
1649
|
reply: "ReplyMode | Literal['one-shot', 'sticky', 'one-time-per-user'] | None" = None,
|
|
1648
1650
|
content_format: "ContentFormat | Literal['plain', 'markdown'] | None" = None) -> "list[Subtask]":
|
|
1649
1651
|
"""Append a subtask to every member instance's chain atomically — or
|
|
@@ -1661,7 +1663,7 @@ class TaskGroup:
|
|
|
1661
1663
|
ids = [t.task_id if isinstance(t, Task) else t for t in instances]
|
|
1662
1664
|
return self._client._append_subtasks_to_group(
|
|
1663
1665
|
self, instances=ids, title=title, content=content, inputs=inputs,
|
|
1664
|
-
links=links, files=files, auto_commit=auto_commit, critical=critical,
|
|
1666
|
+
links=links, files=files, auto_commit=auto_commit, critical=critical, priority=priority, critical_volume=critical_volume,
|
|
1665
1667
|
reply=reply, content_format=content_format,
|
|
1666
1668
|
)
|
|
1667
1669
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|