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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.5
2
2
  Name: simplepush
3
- Version: 3.6.1
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); `critical=True` sends an iOS
117
- Critical Alert.
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); `critical=True` sends an iOS
67
- Critical Alert.
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.6.1"
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
- if critical:
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
- if critical:
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
- if critical:
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